How to use JMS Appender? - java

Inmy research about JMS Appenders I've found turorial1 and tutorial2 . I've tried to follow them, but I couldn't run example program.
Fistly I created file log4j.properties
log4j.rootLogger=INFO, stdout, jms
#
log4j.logger.org.apache.activemq=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c - %m%n
#
log4j.appender.jms=org.apache.log4j.net.JMSAppender
log4j.appender.jms.InitialContextFactoryName=org.apache.activemq.jndi.ActiveMQInitialContextFactory
log4j.appender.jms.ProviderURL=tcp://localhost:61616
log4j.appender.jms.TopicBindingName=logTopic
log4j.appender.jms.TopicConnectionFactoryBindingName=ConnectionFactory
and jndi.properties
topic.logTopic=logTopic
Then I added Receiver.java to my project
public class Receiver implements MessageListener {
public Receiver() throws Exception {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection conn = factory.createConnection();
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
MessageConsumer consumer = sess.createConsumer(sess.createTopic("logTopic"));
consumer.setMessageListener(this);
Logger log = Logger.getLogger(Receiver.class);
log.info("Test log");
Thread.sleep(1000);
consumer.close();
sess.close();
conn.close();
System.exit(1);
}
public static void main(String[] args) throws Exception {
new Receiver();
}
#Override
public void onMessage(Message message) {
try {
// receive log event in your consumer
LoggingEvent event = (LoggingEvent)((ActiveMQObjectMessage)message).getObject();
System.out.println("Received log [" + event.getLevel() + "]: "+ event.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
I need make Receiver to gather all logs from project, but I cannot even run this simple example. Probably I don't know how to configure it correctly, because I get this output:
log4j:WARN No appenders could be found for logger (org.apache.activemq.transport.WireFormatNegotiator).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Did I miss adding some lines in code or some files to classpath? I'm new to log4j.
EDIT:
I set Logger in AspectJ class. But I think that also in Receiver Logger is created and log is sent, so probably it should be done in Receiver, not in other class in my project.
static final Logger logger = Logger.getLogger(ReportingAspect.class);
#Before("setLoggingFile()")
public void setProperties() {
PropertyConfigurator.configure("log4j.properties");
}
ProjectJMS
|
\_ src
| \_ packages...
\_jndi.propeties
\_log4j.properties

To configure log4j use :
-Dlog4j.configuration= path to config file
Path to conf file CAN be:
À file in a path outside of classpath , if so préfix it with file:/// , example:
-Dlog4j.configuration=file:/c:/foobar.lcf
Else in classpath in That case:
-Dlog4j.configuration=foobar.lcf where foobar.lcf is at root of your source folder
See:
http://logging.apache.org/log4j/1.2/manual.html
For jms:
-Add jms.jar at least to classpath
ensure you have a JMS broker running ( activemq for example)
Regards
Philippe

You need to move the log4j.properties under 'src' folder so it'll be included in the classpath, since it's not there it is not being loaded.

Have you validated, that your Method setProperties() is called before you used your logger?
Usually that kind of error only pops up, when either the configuration file (log4j.properties) was not found while initializing log4j by PropertyConfigurator, or you tried to log something before you initialized log4j with your PropertyConfigurator.
First your should make sure, that setProperties() is called the way you expect it to be called and if this should work you could try to validate if the configuration can be loaded. From what I see, I guess your configuration file should be found. To validate this, you could load the configuration in several steps to make sure, it was found:
Properties props = new Properties();
props.load( new FileInputStream( "log4j.properties" ) );
PropertyConfigurator.configure( props );
If your configuration will not be found, you'll receive a FileNotFoundException.

Related

log4j not logging when "Task" is in the log message?

It seems like Log4j is not logging any message containing "Task" using a ConsoleAppender.
public class Main
public static void main(String[] args)
{
Log log = LogFactory.getLog("Main");
log.info("'task' is logged, but");
log.info("'Task' is not logged ?!");
// wait for logging to finish
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
log4j.properties:
log4j.rootLogger = TRACE, CA
log4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.conversionPattern=%d{HH:mm:ss.SSS} %-5p %c.%M - %m%n
I use commons-logging 1.2, log4j 1.2.17, openjdk version "13.0.2" 2020-01-14
Is this a bug? A FileAppender works normally. I can also System.out.println("Task") and see it on the console, so it is not my IDE filtering anything.
I would be happy if someone can try this and verify it, because I am super confused.
It turns out that my IntelliJ IDEA plugin Grep Console was filtering lines with .*Task.* due to import of the company configuration.
In IntelliJ, go to Settings > Other Settings > Grep Console > Input filtering. Check if there is any unexpected.

java.util.logging - How to force all Loggers to obey given format from within the app's runtime? (HSQLDB)

In my app, I would like some way of formatting.
For that purpose, I wrote a SingleLineFormatter extends Formatter.
Now I am trying to set all Loggers to use it, but can't figure that out.
LogManager.getLogManager().readConfiguration((InputStream) configIS);
Collections.list(LogManager.getLogManager().getLoggerNames()).forEach(
loggerName -> {
List<Handler> handlers = Arrays.asList(Logger.getLogger(loggerName).getHandlers());
System.out.println(" * Logger " + loggerName + ": " + handlers.size());
handlers.forEach(handler -> System.out.println(" HF: " + handler.getFormatter()));
//handlers.forEach(handler -> handler.setFormatter(new SingleLineFormatter()));
}
);/**/
log.info("Logging test");
This reads the config, applies it to all handlers that are found.
Oct 02, 2018 10:42:10 PM cz.dynawest.logging.LoggingUtils initLogging
INFO: Log config file not found: #/logging.properties Using LoggingUtils' default.
* Logger cz.dynawest.csvcruncher.App: 0
* Logger global: 0
* Logger cz.dynawest.logging.LoggingUtils: 0
2018-10-02 22:42:10 INFO cz.dynawest.logging.LoggingUtils initLogging: Logging test
* Logger : 2
HF: cz.dynawest.logging.SingleLineFormatter#34c45dca
HF: cz.dynawest.logging.SingleLineFormatter#52cc8049
However the rest of the Loggers still use whatever they were configured with. Probably just JUL's default.
Oct 02, 2018 10:42:10 PM org.hsqldb.persist.Logger logInfoEvent
INFO: checkpointClose start
I know I can manage this from JUL's logging.properties within my JVM.
But I want to distribute the app, and want all the log messages to be formatted the same way.
How can I force all messages going to JUL to be formatted with my Formatter?
There is -Djava.util.logging.config.file=/path/to/app.properties, but that's out of scope for my particular case. (And doesn't work anyway.)
Update: It looks like the third party logging doesn't go through JUL. So the question is - if that's true, how do I configure the other frameworks?
Here is the file that's being loaded to LogManager. There are quite some experiments so not everythign is correct.
# Handlers
handlers = java.util.logging.ConsoleHandler java.util.logging.FileHandler
# Console
# The logging of the app actually reacts to this line.
java.util.logging.ConsoleHandler.formatter = cz.dynawest.logging.SingleLineFormatter
#java.util.logging.ConsoleHandler.formatter = cz.dynawest.logging.SimplestFormatter
java.util.logging.ConsoleHandler.level = ALL
# File
java.util.logging.FileHandler.level = ALL
java.util.logging.FileHandler.pattern = app.log
java.util.logging.FileHandler.formatter = cz.dynawest.logging.SingleLineFormatter
java.util.logging.FileHandler.limit = 0
java.util.logging.FileHandler.append = true
# Default global logging level.
.formatter = cz.dynawest.logging.SimplestFormatter
.level = INFO
#global.formatter = cz.dynawest.logging.SimplestFormatter
#root.formatter = cz.dynawest.logging.SimplestFormatter
#cz.dynawest.csvcruncher.App.formatter = cz.dynawest.logging.SimplestFormatter
#cz.dynawest.csvcruncher.App.handlers = java.util.logging.ConsoleHandler
#.useParentHandlers = false
# Various customizations.
org.apache.commons.beanutils.converters.level=INFO
In my app, I would like some way of formatting. For that purpose, I wrote a >SingleLineFormatter extends Formatter
Since JDK 7 the java.util.logging.SimpleFormatter supports a one line format.
This reads the config, applies it to all handlers that are found.
JUL will only load handlers when the logger is demanded by code. It is therefore possible to miss handlers because the loggers themselves haven't been created yet.
How can I force all messages going to JUL to be formatted with my Formatter?
There is -Djava.util.logging.config.file=/path/to/app.properties, but that's out of scope for my particular case. (And doesn't work anyway.)
You are already accessing the LogManager so you can set properties from Java like so:
private static void loadProperties() {
Properties props = new Properties();
props.put("java.util.logging.ConsoleHandler.formatter", "cz.dynawest.logging.SingleLineFormatter");
props.put("org.apache.commons.beanutils.converters.level", "INFO");
try(ByteArrayOutputStream out = new ByteArrayOutputStream()) {
props.store(out, "");
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
}
If you are running JDK 9 or newer then you should use LogManager.updateConfiguration(java.util.function.Function) instead.
It looks like the third party logging doesn't go through JUL. So the question is - if that's true, how do I configure the other frameworks?
You'll have to determine if the frameworks are routing to one another. You should only have to change the format of the framework that is publishing records to a output source.
In attempts to conform to what the lib might want me to use for logging, I switched to SLF4J and Logback. Didn't help.
So I looked at the particular library that causes the logging issues - HSQLDB.
The problem is that it does some attempts to master all common frameworks and bypasses my attempts to configure it externally. Here is an example: FrameworkLogger
Then I found in the HSQLDB manual:
HyperSQL also supports log4J and JDK logging. The same event information that is passed to the internal log, is passed to external logging frameworks. These frameworks are typically configured outside HyperSQL. The log messages include the string "hsqldb.db." followed by the unique id (a 16 character string) of the database that generated the message, so they can be identified in a multi-database server context.
As the default JDK logging framework has several shortcomings, HyperSQL configures this logging framework for better operation. If you do not want HyperSQL to configure the JDK logging framework, you should include the system level property hsqldb.reconfig_logging=false in your environment.
I tried setting the hsqldb.db. Logger but that didn't work.
So I guess I'll stick with JUL, and turn off the hsqldb.reconfig_logging=false.
By the way, here is a good review of JUL config.
One way is to a static String across application such as
private static Logger logger = Logger.getLogger("some_value");

Log4J SMTPAppender Java

I want to send a mail notification in a java application via log4j. However the first try with configurated log4j.properties file, worked like charm. But since I want a dynamic subject, which is generated in runtime, I tried the following commands, with no success:
final static Logger logger = Logger.getRootLogger();
...
public static mail(String msg, String subj) {
SMTPAppender mailAppend = new SMTPAppender();
mailAppend.setBufferSize(3);
mailAppend.setSMTPHost("smtphostname");
mailAppend.setTo("ex#mple.com");
mailAppend.setSubject(subj);
logger.addAppender(mailAppend);
logger.error(msg);
}
output:
log4j:ERROR Message object not configured.
So did I miss a necessary getter?
An SMTPAppender can be configured either using a xml or properties
file or manually using the setters. When you use the setters, you need
to activate the options by calling the function activateOptions or
else you would get the "ERROR Message object not configured" message.
This is to ensure that the options would only become effective when
all the related options have been set (e.g. one would not want to have
the host setting become effective before the port is set).
FROM : https://community.oracle.com/thread/1758275?start=0&tstart=0

java.util.logging.Logger prints the Message twice in console

I am running a jar file in a console and I put logger so I can trace the if there are any errors. However, the message info prints twice in the console. Can I prevent this?
My code:
public static void main(String[] args) {
Logger log = Logger.getLogger("Logger");
log.setLevel(Level.ALL);
ConsoleHandler handler = new ConsoleHandler();
handler.setFormatter(new SimpleFormatter());
handler.setLevel(Level.ALL);
log.addHandler(handler);
log.log(Level.INFO, "Reading Configuration File");
}
Console:
Jul 22, 2015 9:30:33 PM com.ouc.mv90.conversion.CSVtoMV90Converter main
INFO: Reading Configuration File
Jul 22, 2015 9:30:33 PM com.ouc.mv90.conversion.CSVtoMV90Converter main
INFO: Reading Configuration File
Get ready for a facepalm. This question is basically a duplicate of this SO question, but I am giving an answer anyway.
What is happening is that your Logger class already has a default handler which prints to the System.out console. I expect that just the following code will generate output in your console:
Logger log = Logger.getLogger("Logger");
log.setLevel(Level.ALL);
log.log(Level.INFO, "Reading Configuration File");
But you have gone above and beyond this by adding a second handler which also is directed towards the console. Remove this second handler and that should take care of duplicate messages.
I have run into this problem and in my case the solution was:
Logger logger = Logger.getLogger("Logger");
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.ALL);
logger.addHandler(consoleHandler);
logger.setLevel(Level.ALL);
logger.setUseParentHandlers(false);
Notice the last line that calls to setUseParentHandlers. Without this line I get duplicate logs. I have checked at run time that in my case the number of handlers returned by logger.getHandlers() is just 1 after adding my console handler.
If I try
Logger logger = Logger.getLogger("Logger");
logger.setLevel(Level.ALL);
logger.log(Level.INFO, "Reading Configuration File");
logger.log(Level.FINE, "another message");
in this case I don't get duplicate logs but I don't get anything finer than INFO level either.
Just remove all handlers before add it to your logger, like :
for (Handler handler : logger.getHandlers()) { logger.removeHandler(handler);}
public static void main(String[] args) {
Logger log = Logger.getLogger("Logger");
log.setLevel(Level.ALL);
log.log(Level.INFO, "Reading Configuration File");
}
The above code itself is sufficient to print your log once with it's default log handler. When you add handlers, it will only print in the console using it's default handler, the logging is also directed to your all added handlers to print. Since you are adding another console handler to your logger, veerything will get printed (logged on the console) twice.

Avoiding Multiple Logging of Same Message Due to Default behaviour in Log4j

I am working in Grails application and want to log messages in different files. I want to log exceptions, normal and API logs in different files. But according to Log4j general roles, If we set logger level to 'Info' then warn and error messages will also start logging in this file while I want to log error messages in different file. So, thus my error messages will be logged twicely in error file and in info file too. While I want that 'info' logger log just 'info' level messages not 'error' level messages too. And 'error' logger just log error messages.
Below is my Log4j Configuration:
log4j = {
def layoutPattern = new PatternLayout("[%d{ISO8601}] %m \r\n")
def dailyRollingInfoFile = new DailyRollingFileAppender(
name:"rollingInfoFileAppender",
layout: layoutPattern,
//Path of the Log File
fileName:"C:\\MS-Logs\\Application\\MSLogs.log",
datePattern: "'.'dd-MM-yyyy")
def dailyRollingExceptionFile = new DailyRollingFileAppender(
name:"rollingExceptionFileAppender",
layout: layoutPattern,
//Path of the Log File
fileName:"C:\\MS-Logs\\Exceptions\\ExceptionLogs.log",
datePattern: "'.'dd-MM-yyyy")
def dailyRollingExceptionAPIFile = new DailyRollingFileAppender(
name:"rollingAPIFileAppender",
layout: layoutPattern,
//Path of the Log File
fileName:"C:\\MS-Logs\\API\\MS-NotificationsLogs.log",
datePattern: "'.'dd-MM-yyyy")
//For logging exceptions stack trace
appenders {
appender dailyRollingInfoFile
appender dailyRollingExceptionFile
appender dailyRollingExceptionAPIFile
}
root {
info 'rollingInfoFileAppender', additivity: false
debug 'rollingAPIFileAppender', additivity: false
error 'rollingExceptionFileAppender'
}
}
And Now, this is how I add filters:
dailyRollingExceptionFile.addFilter(new org.apache.log4j.varia.LevelMatchFilter(levelToMatch:'ERROR', acceptOnMatch: true))
dailyRollingExceptionFile.addFilter(new org.apache.log4j.varia.DenyAllFilter())
//To make it sure that It will just Log, Messages by Info Logger
dailyRollingInfoFile.addFilter(new org.apache.log4j.varia.LevelMatchFilter(levelToMatch:'INFO', acceptOnMatch: true))
dailyRollingInfoFile.addFilter(new org.apache.log4j.varia.DenyAllFilter())
//To make it sure that It will just Log, Messages by API Logger
dailyRollingAPIFile.addFilter(new org.apache.log4j.varia.LevelMatchFilter(levelToMatch:'DEBUG', acceptOnMatch: true))
dailyRollingAPIFile.addFilter(new org.apache.log4j.varia.DenyAllFilter())
How, It may be possible to avoid same message being logged twicely in different files ? How can we log messages in different files without being repeating it in other file ?
Thanks for your Time :)
I believe Log4j's LevelMatchFilter allows you to do what you're after:
def dailyRollingInfoFile = new DailyRollingFileAppender(...)
dailyRollingInfoFile.addFilter(new org.apache.log4j.varia.LevelMatchFilter(levelToMatch:'INFO', acceptOnMatch: true))
dailyRollingInfoFile.addFilter(new org.apache.log4j.varia.DenyAllFilter())
The DenyAllFilter drops the messages that the LevelMatchFilter does not match (ie. everything other than level INFO)

Categories

Resources