system property not replaced with the date and time for new log4j log filename for every run - log4j

I have the below lines as part of log4j.properties file.
property.filename=logs
appenders=file
appender.file.type=File
appender.file.name=LOGFILE
appender.file.fileName=${filename}/propertieslogs_${current.date}.log
appender.file.layout.type=PatternLayout
appender.file.layout.pattern=[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %m%n
appender.file.append=false
loggers=file
logger.file.name=com.utils
logger.file.level=info
logger.file.appenderRefs=file
logger.file.appenderRef.file.ref=LOGFILE
rootLogger.level=info
rootLogger.appenderRefs=stdout
rootLogger.appenderRef.stdout.ref=STDOUT
And, I have 3 java files. The first one has the main function. And, I have included the below lines to store the current date in the system property.
static {
SimpleDateFormat dateTimeFormat = new SimpleDateFormat("dd-MM-yyyy-hh-mm-ss");
System.setProperty("log4j.logger.dateTime", dateTimeFormat.format(new Date()));
}
The 2nd java file has the logger class defined.
public static Logger logger = LogManager.getLogger(CustomerDetails.class);
And, it contains the logger.info, logger.warn, and logger. error statements.
The 3rd file contains the reusable methods called from 2nd file.
Now, when the 1st file containing main function executed then the log file is created as expected. But, not with the required name. The log file name looks like this.
propertieslogs_${current.date}.log
Why the 'current.date' from system property not updated in the log file created.
Appreciate any help on this please...

Related

Trying to figure out activeweb logging to a separate file

I am trying to use the default active web library to log everything to a separate log file. Right now I'm running everything under IntelliJ (via mvn jetty:run) and all the logging is coming out to the console only.
I tried added a log4j.properties file in the WEB-INF directory; didn't work (I have not added log4j dependency to my pom as I don't want it in there).
Looking a slf4j, I cannot find any properties or config file that let's me define how I would log to a specific log file. And, I'm not sure what logging AW uses, so it's hard to see what I need to configure.
Stuck at this point, and just googling and reading thru the slf4j site to try to get this working.
I general, if you want logging done by Log4j and Slf4j, you will need to add appropriate dependencies. Here is the configuration from one of our projects:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
this will bring appropriate deps.
Here is the contents of the log4j.properties file.
log4j.rootLogger=INFO, ${logger-name}, SPLUNK
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.SPLUNK=org.apache.log4j.DailyRollingFileAppender
log4j.appender.SPLUNK.File=${catalina.home}/logs/worker-splunk.log
log4j.appender.SPLUNK.Append=true
log4j.appender.SPLUNK.Encoding=UTF-8
# This is a filter that will filter out junk we do not want to sent to Splunk
log4j.appender.SPLUNK.filter.1=app.utils.SplunkLogFilter
log4j.appender.SPLUNK.layout=org.javalite.logging.JsonLog4jLayout
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.FILE.File=${catalina.home}/logs/worker.log
log4j.appender.FILE.Append=true
log4j.appender.FILE.Encoding=UTF-8
log4j.appender.FILE.layout=org.javalite.logging.JsonLog4jLayout
The logger-name is a Maven- filtered property. Locally it is resolved to CONSOLE and when the app is built, it resolves to FILE. This way, we can observe log on the console during development.
The class SplunkLogFilter looks like this:
import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.LoggingEvent;
public class SplunkLogFilter extends Filter {
private static final String[] EXCLUDED_LOGGERS = new String[]{"***ServiceImpl", "app.utils.ProcessUtil"};
private static final String[] EXCLUDED_MESSAGES = new String[]{"****Command"};
#Override
public int decide(LoggingEvent event) {
String loggerName = event.getLoggerName();
for (String excludedLogger : EXCLUDED_LOGGERS) {
if(loggerName.equals(excludedLogger)){
return Filter.DENY;
}
}
String message = event.getMessage().toString();
for (String excludedMessage : EXCLUDED_MESSAGES) {
if(message.contains(excludedMessage)){
return Filter.DENY;
}
}
return Filter.NEUTRAL;
}
}
So, we are logging into two files in parallel, where one is shipped into Splunk.
The Splunk file is smaller, so we pay less for Splunk, but we retain full files just in case.

Log4Net Retrieve Appenders Programmatically

I have a separate Log4Net.config file with 2 appenders and 2 loggers, 1 logger for each appender. There is no <Root /> logger.
I am trying to add code to my application that will retrieve the filename for the logger to allow the user to view the log files for each of the appenders from an application menu selection. I have tried the below code but it returns no appenders. What did I miss?
I should also have mentioned that I am using the slf4net.log4net facade
log4net.Repository.ILoggerRepository repo = LogManager.GetRepository();
foreach (log4net.Appender.IAppender appender in repo.GetAppenders())
{
string x = appender.Name;
}
I found the answer in this post log4Net config in external file does not work. After adding the ConfigFile name to the assemblyinfo entry it began working

Avoiding of printing full package name of method in log4j

I have an API that uses log4j for logging. When I have used the API in my project, though log statements related to project printed with ontl method name, but log statements coming from API is printed full package name format.
In log4j.properties file I am using "%c" (lowercase).
How I can force all project log statements get printed only method name.
Lets say;
I have two classes Main.java and AlarmCategoryImpl.java
AlarmCategroryImpl.java is located on API class, Main.java is defined in my project class.
static Logger logger = Logger.getLogger(AlarmCategoryImpl.class);
static Logger logger = Logger.getLogger(Main.class);
and its log4j output.
2012-12-01/18:13:22.220/EET [INFO][Main->main] starting...
2012-12-01/18:13:22.447/EET [INFO][com.monitor.base.alarmmanagement.alarmconfigurationImpl.AlarmCategoryImpl->copyStructureRecursive] Copying AlarmCategoryImpl
%c means "category name", which is synonymous to "logger name". That means that %c will be expanded to the logger's name.
The logger name is not necessarily the fully-qualified class name. The logger name is the string that is passed in to Logger.getLogger(). Therefore, if you have a class named x.y.z.MyClass, and it has this:
private static final Logger logger = Logger.getLogger("hello");
Then log statements will be generated with hello expanded instead of %c.
That means that the classes in your API are using getLogger(), passing the class name as a parameter. That causes %c to be expanded to the fully-qualified class name when the logs print.
I'm guessing that your non-API classes (in other words, your own project's classes) don't pass-in any value to Logger.getLogger(), or perhaps they use the root logger. To be sure, paste here the line of your code that retrieves the Logger instance.
EDIT as per comment:
Well, is it possible that your Main class is inside the default package? (that is, it is not associated with any package)? If yes, then I don't see any problem.
[INFO][Main->main]: INFO is the level, Main is the class, main is the method.
[INFO][com.monitor.base.alarmmanagement.alarmconfigurationImpl.AlarmCategoryImpl->copyStructureRecursive]: INFO is the level, com.monitor.base.alarmmanagement.alarmconfigurationImpl.AlarmCategoryImpl is the class, copyStructureRecursive is the method.

Programmatically configuring log4net

I'm having the worst time trying to configure log4net properly. First, I need to give some background about how I've been using it so far (and successfully).
My application has a log4net configuration file that defines the FileAppender that it should log all data to. All of my assemblies have an ILog member variable, and set it to LogManager.GetLogger( typeof( myclass)), where myclass is the class that is logging.
Everything works great like this.
Now I also have an assembly that is used slightly differently. It can be instantiated multiple times, and the requirement is that each instance logs to its own file. I was able to get this to work programmatically, and ditching the logging.xml file.
Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Root.Level = log4net.Core.Level.All;
hierarchy.Configured = true;
string module_path = MyCompany.Shared.Utils.FileSystem.GetModulePath();
string folder = module_path + "\\logs\\";
string path = String.Format("{0}{1}-log.txt", folder, name);
_log = LogManager.GetLogger( name);
var fa = new log4net.Appender.FileAppender() { Name = name, File = path, AppendToFile = true};
var layout = new PatternLayout { ConversionPattern = "%date{{yyyy-MM-dd-HH_mm_ss.fff}} [%thread] %-5level %logger - %message%newline" };
layout.ActivateOptions();
fa.Layout = layout;
fa.ActivateOptions();
((Logger)_log.Logger).AddAppender( fa);
This also works great. Now here's where the problem comes in: the above assembly uses another assembly that also uses log4net. However, that assembly is expecting there to be a logger already configured for use, and apparently the way I'm setting up log4net programmatically is preventing that from working.
I have enabled internal log4net debugging, and the error message I see is pretty explicit about the error, but I'm not sure how to (best) solve the problem:
log4net: Logger: No appenders could be found for logger [test_logger] repository [log4net-default-repository]
log4net: Logger: Please initialize the log4net system properly.
log4net: Logger: Current AppDomain context information:
log4net: Logger: BaseDirectory : C:\Sample\bin\Debug\
log4net: Logger: FriendlyName : SampleTestApp.vshost.exe
log4net: Logger: DynamicDirectory:
log4net: Hierarchy: Shutdown called on Hierarchy [log4net-default-repository]
I assume that the logger is created, since I get the same error even if I explicitly use the LoggerFactory to create a "test_logger" logger. So it's just a matter of figuring out how to create the appender for that logger. I have tried to use the previous code to create a FileAppender for this logger, but even though the code runs, I get the same error.
Can anyone suggest things for me to try to get this to work?
EDIT -- I should clarify that I really would like all of the log messages to go into the FileAppender that was created by the test app. I would like to avoid having separate files (one for each assembly).

How do I make log4j create log files on demand only?

We have a modular application where modules have their own log4j logs (i.e. communication log and error log). The appenders and categories for these are all configured in the core log4j XML, but not all modules are always installed.
The DailyRollingFileAppender creates its file regardless of use and that exposes the full set of modules although not present and as some of them are customer specific we'd like to hide logs not in use.
Is there a way to make DailyRollingFileAppender create its file on first use instead of automatically at startup?
I had the same problem, so I have extended the standard FileAppender class and I have created a new LazyFileAppender that is a FileAppender that lazily initialize the log file(creates it only when the first write operation happens).
The LazyFileAppender and some other additions to the standard log4j library can be found into a simple library that I have created : log4j-additions .
You can look at the source to develop your own extension or you can use it as is ...
In Log4j 2, both FileAppender and RollingFileAppender has the parameter "createOnDemand" which can be used to configure to create the log file only when a log event passed to the appender.
Example:
<RollingFile name="LogFile" fileName="test.log" filePattern="test-%i.log.gz" createOnDemand="true">
<Policies>
<SizeBasedTriggeringPolicy size="1MB"/>
</Policies>
<DefaultRolloverStrategy max="5"/>
</RollingFile>
More details here: https://logging.apache.org/log4j/2.x/manual/appenders.html#RollingRandomAccessFileAppender
The file appenders have no option to lazily create the log files - the setFile method automatically creates the file if it doesn't already exist: ostream = new FileOutputStream(fileName, append);
You'll have to extend the appender and overwrite the file initialisation code yourself to get the behaviour you're after.
Extend the standard FileAppender class was unsuccessful for me. So I have found an other solution using appenders programmatically to create log files on demand only (and with timestamp in the name file). I have written these two methods :
public void startLog() {
SimpleDateFormat sdf_long = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
FileAppender fa = new FileAppender();
fa.setName("foo");
fa.setFile(sdf_long.format(new Date()) + ".log");
fa.setLayout(new PatternLayout("%d{HH:mm:ss.SSS} %m%n"));
fa.setThreshold(Level.DEBUG);
fa.setAppend(true);
fa.activateOptions();
Logger.getRootLogger().addAppender(fa);
}
public void stopLog() {
Logger.getRootLogger().getAppender("foo").close();
Logger.getRootLogger().removeAppender("foo");
}
My log4j.properties file only configures the console appender. When I want to start logging I call the startLog() method. When I want to log in an other file I call stopLog() first and then startLog() method.

Resources