Custom logging with log4j2 jdbc appender in java - java

I am trying to log my events in my database using log4j2. Specifically I am using log4j2 jdbc appender in my properties configuration file for that purpose. By using default log4j2 log levels everything works. The log values successfully get inserted in database.
This is my initial appender in my log4j2 properties file:
# JDBC appender
appender.db.type = Jdbc
appender.db.name = databaseAppender
appender.db.tableName = db_name.test
appender.db.cf.type = ConnectionFactory
appender.db.cf.class = com.myproject.ConnectionFactory
appender.db.cf.method = getConnection
appender.db.col2.type = Column
appender.db.col2.name = message
appender.db.col2.pattern = %m
appender.db.col3.type = Column
appender.db.col3.name = category
appender.db.col3.pattern = %M{1}
appender.db.col4.type = Column
appender.db.col4.name = timestamp
appender.db.col4.isEventTimestamp = true
appender.db.col5.type = Column
appender.db.col5.name = log_level
appender.db.col5.pattern = %-5p
appender.db.filter.threshold.type = ThresholdFilter
appender.db.filter.threshold.level = info
appender.db.filter.threshold.onMatch = Accept
appender.db.filter.threshold.onMismatch = Deny
But then I tried to create a custom log level following this log4j2 site https://logging.apache.org/log4j/2.x/manual/customloglevels.html
LOG.log(Level.forName("DIAG", 350), "a diagnostic message");
It successfully logs the event with the defined log level. And even places the data in database since threshold level is info in my jdbc appender. As info intLevel > diag intLevel.
My problem is if I changed the threshold level to diag in my jdbc appender it doesn't work at all i.e.
appender.db.filter.threshold.level = diag
Nothing is inserted in my database. So my first question is why it is not working and please give me any solution if possible.
Another thing is that I twitched around the intLevel of DIAG to 10 like:
LOG.log(Level.forName("DIAG", 10), "a diagnostic message");
And now it is inserting in database but also throws some errors.
2019-05-24 12:06:00,248 main WARN Error while converting string [diag] to type [class org.apache.logging.log4j.Level]. Using default value [null]. java.lang.IllegalArgumentException: Unknown level constant [DIAG].
at org.apache.logging.log4j.Level.valueOf(Level.java:320)
at org.apache.logging.log4j.core.config.plugins.convert.TypeConverters$LevelConverter.convert(TypeConverters.java:288)
at org.apache.logging.log4j.core.config.plugins.convert.TypeConverters$LevelConverter.convert(TypeConverters.java:284)
at org.apache.logging.log4j.core.config.plugins.convert.TypeConverters.convert(TypeConverters.java:419)
at org.apache.logging.log4j.core.config.plugins.visitors.AbstractPluginVisitor.convert(AbstractPluginVisitor.java:149)
at org.apache.logging.log4j.core.config.plugins.visitors.PluginAttributeVisitor.visit(PluginAttributeVisitor.java:45)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.generateParameters(PluginBuilder.java:253)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:135)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:964)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:904)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:896)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:896)
at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:514)
at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:238)
at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:250)
at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:548)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:620)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:637)
at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:231)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:153)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:45)
at org.apache.logging.log4j.LogManager.getContext(LogManager.java:194)
at org.apache.logging.log4j.LogManager.getLogger(LogManager.java:581)
at com.myproject.Main.<clinit>(Main.java:35)
Any help would be greatly appreciated and thank you in advance.

Since you have not defined intLevel in log4j2.properties file so add
customLevel.DIAG =350
where 350 is the intLevel.
This may remove the error.

Related

How to destroy log4j logger instances

I have a code that run concurrently, and for each run it need log something in file. Each execution - new story with unique file.
So, I can't just get the logger for classname, add file appender, write logs, close and remove appender, because when concurrect code run - logger will contains both appenders, and logs will be written to both files.
So, I can create a new logger instance for each execution Logger.getLogger(classname + counter), but how to mark it as garbage after work is done?
P.S. Moreover... I need somethimes print to console from all this loggers.
Maybe I do something wrong, maybe log4j not created for this pattern and I have to implement it. But log4j - priority choose for me, because it already widely used in this big application.
Thank you in advance, Andrei!
You can't destroy / clean up Appender instances. But you can improve the solution you have with Log4j2 toolbox.
Routing things to dynamic files in Log4j is possible, but most of the time a Marker in a file is sufficient, or at least a starting point for more complex routing.
Please do read up on its documentation. Especially the last paragraph is important to your case:
Some important rules about Markers must be considered when using them.
Markers must be unique. They are permanently registered by name so care should be taken to insure that Markers used in your application are distinct from those in the application's dependencies, unless that is what is desired.
Parent Markers can be added or removed dynamically. However, this is fairly expensive to do. Instead, it is recommended that the parents be identified when obtaining the Marker the first time as shown in the examples above. Specifically, the set method replaces all the markers in a single operation while add and remove act on only a single Marker at a time.
Evaluating Markers with multiple ancestors is much more expensive than Markers with no parents. For example, in one set of tests to evaluate whether a Marker matched its grandparent took 3 times longer than evaluating the Marker itself. Even then though, evaluating Markers is inexpensive compared to resolving the callers class name or line number.
Then you can use the marker in the configuration in places where a pattern is expected like this: $${marker:}. I haven't used that in a filename though and doubt that it works, but you can create routing based on the Marker.
I used this simple test script, please note the use of the Marker that is created for each line from the Scanner. In your case it would be created by config or from Servlet input or similar.
package toTest;
import java.util.Scanner;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
public class TestMe {
private final Logger myOneAndOnlyLogger = LogManager.getLogger("MyCentralName");
public static void main(String[] args) {
new TestMe().doMyThing();
}
private void doMyThing() {
Scanner input = new Scanner(System.in);
String line = "";
while(!line.equals("QUIT")) {
System.out.println("Line: ");
line = input.nextLine();
Marker forThisRound = MarkerManager.getMarker(line);
myOneAndOnlyLogger.log(Level.ERROR, forThisRound, "1");
myOneAndOnlyLogger.log(Level.ERROR, forThisRound, "2");
System.out.println("Line done.");
}
}
}
and this log4j2.properties (a rolling file example I had at hand with marker in the pattern):
status = error
name = MarkerExample
#Make sure to change log file path as per your need
property.filename = /tmp/java/marker.log
filters = threshold
filter.threshold.type = ThresholdFilter
filter.threshold.level = debug
appenders = rolling
appender.rolling.type = RollingFile
appender.rolling.name = RollingFile
appender.rolling.fileName = ${filename}
appender.rolling.filePattern = /tmp/java/debug-backup-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} $${marker:} %-5p %c{1}:%L - %m%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size=10MBONE
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 20
loggers = rolling
#Make sure to change the package structure as per your application
logger.rolling.name = MyCentralName
logger.rolling.level = debug
logger.rolling.additivity = false
logger.rolling.appenderRef.rolling.ref = RollingFile

Tomcat logging properties filtering

I have simplified tomcat's logging properties to just this:
handlers = java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=%1$tF %1$TT.%1tL [::] %4$s %3$s %5$s %n
org.springframework.aop.framework.CglibAopProxy.level = ERROR
My issue is that the last line seems to be completely ignored and I keep seeing logs like this:
2018-05-09 10:40:33.159 [::] INFO org.springframework.aop.framework.CglibAopProxy
I am absolutely sure it comes from this logger thanks to the log format I set in the logging.properties.
My issue is that the last line seems to be completely ignored...
It is ignored because ERROR fails to be parsed as valid level. Per the docs:
Valid values are integers between Integer.MIN_VALUE and Integer.MAX_VALUE, and all known level names. Known names are the levels defined by this class (e.g., FINE, FINER, FINEST), or created by this class with appropriate package access, or new levels defined or created by subclasses.
Change your logging line to one of the valid levels that is higher than INFO. Choose one of the following log lines:
org.springframework.aop.framework.CglibAopProxy.level = OFF
org.springframework.aop.framework.CglibAopProxy.level = SEVERE
org.springframework.aop.framework.CglibAopProxy.level = WARNING

Dropwizard custom logger does not dump logs into the file

I need to set maxfile size for my application but currently i am using Dropwizard core version 0.8.4 and its file appender does not support this feature.
So I approached like below by writing a custom appender as updating to latest dropwizard(which support my need) version not an option right now.
private void initLogging(Configuration configuration) throws JoranException {
final File logDir = new File("/tmp/enforcer");
final File logFile = new File(logDir, "wallet.log");
final LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
RollingFileAppender<ILoggingEvent> rollingFileAppender = new RollingFileAppender<ILoggingEvent>();
rollingFileAppender.setFile(logFile.getAbsolutePath());
rollingFileAppender.setName("com.documents4j.logger.server.file");
rollingFileAppender.setContext(loggerContext);
FixedWindowRollingPolicy fixedWindowRollingPolicy = new FixedWindowRollingPolicy();
fixedWindowRollingPolicy.setFileNamePattern(logFile.getAbsolutePath() +"%i.gz");
fixedWindowRollingPolicy.setMaxIndex(7);
fixedWindowRollingPolicy.setContext(loggerContext);
fixedWindowRollingPolicy.setParent(rollingFileAppender);
fixedWindowRollingPolicy.start();
SizeBasedTriggeringPolicy<ILoggingEvent> sizeBasedTriggeringPolicy = new SizeBasedTriggeringPolicy<ILoggingEvent>();
sizeBasedTriggeringPolicy.setMaxFileSize("2KB");
sizeBasedTriggeringPolicy.setContext(loggerContext);
sizeBasedTriggeringPolicy.start();
rollingFileAppender.setRollingPolicy(fixedWindowRollingPolicy);
rollingFileAppender.setTriggeringPolicy(sizeBasedTriggeringPolicy);
rollingFileAppender.start();
System.out.println("Logging: The log is written to " + logFile);
final ch.qos.logback.classic.Logger log = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
log.setLevel(Level.DEBUG);
log.addAppender(rollingFileAppender);
}
#Override
public void run(Configuration configuration, Environment environment) throws Exception
{
initLogging(configuration);
}
My yaml file config is
logging:
level: INFO
org.springframework.retry.support.RetryTemplate: DEBUG
appenders:
- type: file
currentLogFilename: /tmp/enforcer.log
threshold: ALL
archive: true
archivedLogFilenamePattern: /tmp/enforcer-%d.log
archivedFileCount: 5
timeZone: UTC
logFormat: '%-5level [%date{yyyy-MM-dd HH:mm:ss,SSS}] [%X{realdocRequestId}] %logger{15}: %m%n'
Now when i run my application i noticed, even though custom log file (/tmp/enforcer/wallet.log) is created in the particular directory but actual log is not dumped i.e. wallet.log file size is 0 kb where as the log file configured in yaml is created and size is certain kb and goes on increasing as log event is generated.
I am not able figure out what is wrong im doing, help will be appreciated.
your logger doesn't log anything because you never set an encoder to it. Set a breakpoint in:
OutputStreamAppender#start() and you will see that there is no encoder.
It will work once you add:
LayoutWrappingEncoder<ILoggingEvent> layoutEncoder = new LayoutWrappingEncoder<>();
DropwizardLayout formatter = new DropwizardLayout(loggerContext, TimeZone.getDefault());
formatter.setPattern("[%level] [%h] %d{yyyy-MM-dd'T'HH:mm:ss.SSS'Z', UTC} [%thread] [%logger] %msg%n");
layoutEncoder.setLayout(formatter);
formatter.start();
rollingFileAppender.setEncoder(layoutEncoder);
Of course you can define whichever format you like (and formatter).
But keep in mind that this is a fairly hacky example of what you try to achieve. You now have 2 points in code where you configure logging (DW and your own). You have yaml configured logging as well as your own. I recommend investing a bit of work and adding a proper AppenderFactory that you can use.
Hope that helps,
Artur

How to disable logging hibernate "Table not found" message

How do I disable logging output from Hibernate for:
HHH000262: Table not found: ...
I have the following log4j.properties:
log4j.rootLogger=WARN, stdout, stderr
log4j.logger.org.apache=WARN
log4j.logger.org.springframework=WARN
log4j.logger.org.hibernate=ERROR
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Threshold = TRACE
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %m%n
log4j.appender.stdout.filter.filter1=org.apache.log4j.varia.LevelRangeFilter
log4j.appender.stdout.filter.filter1.levelMin=TRACE
log4j.appender.stdout.filter.filter1.levelMax=INFO
# configure stderr for ERROR and WARN
log4j.appender.stderr = org.apache.log4j.ConsoleAppender
log4j.appender.stderr.Threshold = WARN
log4j.appender.stderr.Target = System.err
log4j.appender.stderr.layout = org.apache.log4j.PatternLayout
log4j.appender.stderr.layout.ConversionPattern = %p: %m%n
The log4j.logger.org.hibernate=ERROR does eliminate other Hibernate INFO messages such as opening the database and such. The "Table not found" messages are logged as INFO (I confirmed in the source code of hibernate).
I do not want to see the "Table not found" messages because I am using "update" mode to auto-create and update the tables.
What am I missing?
It looks like there is a bug in the org.hibernate.tool.hbm2ddl.DatabaseMetadata LOG static constant. It is constructed like so...
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, DatabaseMetaData.class.getName());
The subtle bug is that the value passed into the category parameter is the DatabaseMetaData class (notice the capital D in MetaData), which is from the package java.sql. As a result, you have to specify the logging level using...
log4j.logger.java.sql.DatabaseMetaData=WARN
In Log4j you can specify a logging level for specified package, class or logger identified by string. You just simply write this in log4j.properties file:
log4j.logger.<your package> = DEBUG|INFO|OFF|WARN...

log4j in grails : how to log into file?

I have this log4j configuration in my grails config.groovy
log4j = {
error 'org.codehaus.groovy.grails.web.servlet', // controllers
'org.codehaus.groovy.grails.web.pages' // GSP
warn 'org.mortbay.log'
appenders {
rollingFile name:'infoLog', file:'info.log', threshold: org.apache.log4j.Level.INFO, maxFileSize:1024
rollingFile name:'warnLog', file:'warn.log', threshold: org.apache.log4j.Level.WARN, maxFileSize:1024
rollingFile name:'errorLog', file:'error.log', threshold: org.apache.log4j.Level.ERROR, maxFileSize:1024
rollingFile name:'custom', file:'custom.log', maxFileSize:1024
}
root {
info 'infoLog','warnLog','errorLog','custom', stdout
error()
additivity = true
}
}
the infoLog,warnLog and errorLog was from the previous question ... they were working well.
now I add new RollingFile wit name "custom" ...
I tried to log from my controller and service using log.info("something .... ${obj}");
but it seems that message was not inserted into custom.log, do I need to add something to the configuration ?
thank you !!
just got answer from the grails' mailing list:
i just need to add
debug "grails.app"
bellow warn "org.mortbay.log"
case closed ! :)
I have exact the same jetty/tomcat env's. Spent hours to figure it out. The trick is to define the file location (a relative path in my case) as a global variable inside Config.groovy, customized it in the environment blocks, and use the variable location inside log4j closure. Sample code is at: http://denistek.blogspot.com/2010/02/grails-environment-specific-logging-to.html
please see Log4j: How to write to a specific appender?
After all the solution is to put the additivity setting to the package configuration:
info specialLog:'activityLog', additivity:false

Categories

Resources