In my output I have JUL logging messages from Jersey like this
03.12.2010 14:14:55 com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
Programmatically I wanted to swich them off so I tried
Logger.getLogger("com.sun.jersey.api.core.PackagesResourceConfig").setLevel( Level.SEVERE );
or
Logger.getLogger("com.sun.jersey").setLevel( Level.SEVERE );
but this don't work.
Funny enough this global configuration works:
Logger.getLogger( "com" ).setLevel( Level.SEVERE );
or
Logger.getLogger( "" ).setLevel( Level.SEVERE );
WHY?
I had some problems with this so I thought I'd put code in with imports to avoid confusion. I tested this and it works in my mini webserver configuration. Again, I included the whole server implementation for completeness.
import java.io.IOException;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.core.UriBuilder;
import com.sun.jersey.api.container.httpserver.HttpServerFactory;
import com.sun.jersey.api.core.PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.net.httpserver.HttpServer;
public class WebServer {
private HttpServer webServer;
private final static Logger COM_SUN_JERSEY_LOGGER = Logger.getLogger( "com.sun.jersey" );
static {
COM_SUN_JERSEY_LOGGER.setLevel( Level.SEVERE );
}
public void start() throws IOException {
System.out.println("Starting WebServer\n");
webServer = createHttpServer();
webServer.start();
System.out.println(String.format("\nWeb Server started:" + "%sapplication.wadl\n", getURI()));
}
public void stop() {
webServer.stop(0);
}
public static HttpServer createHttpServer() throws IOException {
ResourceConfig rc = new PackagesResourceConfig("com.daford");
return HttpServerFactory.create(getURI(), rc);
}
private static URI getURI() {
return UriBuilder.fromUri("http://localhost/").port(4444).build();
}
}
The loggers returned by Logger.getLogger() are WeakReferences. So directly after you set the appropriate level, they may get garbage collected, since you do not retain any reference to it, thus deleting your setting.
Store your logger in a variable with an appropiate scope to keep your settings.
Credits to John Smith above, but here is the one line answer with the right package name:
Logger.getLogger("org.glassfish.jersey").setLevel(Level.SEVERE);
No imports necessary, these come from java.util.
And let this be a lesson to all of you in Unix Philosophy's rule of silence: when you have nothing erroneous to say, shut the hell up.
Essentially each logger instance has a loglevel. However, when you retrieve a logger instance via Logger.getLogger() you are more than likely creating a new instance of a new logger. Since you aren't keeping a reference to the Logger it instantly goes out of scope and your change is lost.
The reason Logger.getLogger("") and Logger.getLogger("com") work for you is that persistent loggers are already being created for those two levels, which means you are retrieving those loggers which remain persistent.
One simple fix is to use the LogManager class in JUL:
LogManager.getLogManager().setLevel("com.sun.jersey", Level.SEVERE);
There is a great article on O'reilly that should help you.
Related
I'm upgrading an old system that was a batch job that used Camel Main to continue running, so that it can basically loop and query a database every few seconds. It also uses Spring for configuration, but doesn't use Spring Boot. It was on Camel 2.x and I'm having to upgrade it to Camel 3.14. The Main class has changed in that time. In addition to being moved to a different package, it has lost the method it was using to add the Spring context, which was setApplicationContextUri("app-context"). There is a configure() method on Main now, but I still don't see a way of adding a Spring context to Main.
Looking at javadocs for the new Main, I see there are methods in MainSupport that reference CamelContext, but they seem to be about creating a blank CamelContext. There is also an autoconfigure(CamelContext) which takes in CamelContext, but it's protected, so I don't see how to call it. I guess without extending Main, which I don't see any use cases or examples for.
Alternatively, if there's a way to do this without using Main, I'm open to that as well.
The Spring and CamelContext are mainly used to set up beans like dataSources and Properties. The Route is defined in the same class that contains the java main() method that is called from the script used to start the whole process (this is the old version):
package com.foo.email.ffdb.listener;
import java.util.Properties;
import javax.annotation.Resource;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spring.Main;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import com.foo.email.ffdb.util.FireFrgtConstants;
public class EmailDBListener extends RouteBuilder {
private static Logger log = LogManager.getLogger(EmailDBListener.class.getName());
private static String routeId = FireFrgtConstants.EMAIL_ROUTE_ID;
#Autowired
private EmailDBProcessor emaiDBProcessor;
#Resource
private Properties emailProperties;
public static void main(String[] args) throws Exception {
System.out.println("STARTING EMAILDBLISTENER");
log.debug("Starting Email Batch ");
Main main = new Main();
main.setApplicationContextUri("app-context.xml");
main.run();
log.info("Email Batch Started:");
}
#Override
public void configure() throws Exception {
log.debug("configure() ");
from(configureSqlTimer())
.routeId(routeId)
.to("sqlComponent:{{SQL.READ_EMAIL_REQUESTS}}")
.bean("fireForgetServiceMapper", "readEmailRequests")
.process(emaiDBProcessor);
}
private String configureSqlTimer() {
log.debug("configureSqlTimer() ");
String pollingTime = emailProperties.getProperty(FireFrgtConstants.POLLING_TIME);
String sqlTimer = "timer://pollFireFrgtTable?period=" + pollingTime + "s";
return sqlTimer;
}
}
I just had the wrong Main. There is one in camel-main, and another in camel-spring-main. I just needed to use the camel-spring-main, and it started running and staying alive.
Except for a transaction problem I am creating another question for...
But the main program is running
I've found a few examples (even on Stack Overflow) of some programmatic configuration of Logback logging appenders, but as much as I've incorporated into my own setup hasn't worked for me so far. Some examples produce an actual Logger instance, but considering I've already got a Logger being statically instantiated within my class, I want to be able to programmatically enable an Appender that I've defined for unit testing purposes.
Here is my custom appender:
package org.example.logging;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import java.util.ArrayList;
import java.util.List;
// Credit to https://stackoverflow.com/a/29077499/5476186
public class TestAppender extends AppenderBase<ILoggingEvent> {
private static List<ILoggingEvent> events = new ArrayList<>();
#Override
protected void append(ILoggingEvent e) {
events.add(e);
}
public static List<ILoggingEvent> events() {
return List.copyOf(events);
}
public static void clear() {
events.clear();
}
}
And in my testing code, I'm trying to configure my TestAppender to "kick in" so that, after invoking this method in my test setup, I can capture the logs and validate them:
package org.example.logging;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.LoggerFactory;
// ...
// Mostly modeled after https://stackoverflow.com/a/7825548/5476186
private static void startAppender() {
LoggerContext logCtx = (LoggerContext) LoggerFactory.getILoggerFactory();
TestAppender appender = new TestAppender();
appender.setContext(logCtx);
appender.setName("TEST");
// I was hoping this would statically allow the appender to kick in,
// but all of the examples then attach this appender to a Logger instance.
appender.start();
}
Obviously, this isn't working for me. So I guess I have two contingent questions.
Is this possible and, if so, how can I make it work?
If this is not possible, what's the cleanest way to accomplish what I'm trying to do? (Enable/disable appenders during testing without having to manually mess with a config file.)
In one of the threads linked above, I found this answer which looks like one possible solution is to modify the text in the configuration file and to force a reload, but that doesn't seem super clean to me. Another option would be to create my own wrapper Logger factory which I could use to provide loggers with my TestAppender during test execution with dependency injection. I'll probably be creating a wrapper anyway, even though I'm using SLF4J.
Side note: I know that my test code as currently written is pretty tightly coupled with Logback instead of SLF4J, so I'm open to criticism/advice on that issue, too.
If you're using slf4j in your production code, then there is already a project that can help in testing: Its called slf4j-test
In a nutshell, it provides an API to retrieve a "test logger" in the test that will keep all the logged messages in memory so that you'll be able to verify them.
So that you:
Execute a method that logs something
Retrieve a test logger
call getLoggingEvents() on the test logger and verify the logged events
The link that I've provided contains an example of the API as well as maven integration example.
If, alternatively you would like to use logback directly for the tests or something, there is already a ListAppender shipped as a part of logback distribution that allows retrieval of events that have passed through the appender. You can add it programmatically to the logger and use inside the test.
Here you can find a comprehensive example of doing that
In short: the object "logger" is not recognized unlike in many tutorials.
The problem on its own is not very serious and I can easily go around it. However it is very frustrating to see this "logger" stays in red in my intellIj editor. I am going through docs and blogs and I don't see what the problem is.
My snippet:
#Override
public void insertTicketStatut(TicketStatut pTicketStatut) {
String vSQL = "INSERT INTO statut {id, libelle} VALUES {:id, :libelle}";
BeanPropertySqlParameterSource vParams = new BeanPropertySqlParameterSource(pTicketStatut);
NamedParameterJdbcTemplate vJdbcTemplate = new NamedParameterJdbcTemplate(getDataSource());
try {
vJdbcTemplate.update(vSQL, vParams);
} catch (DuplicateKeyException pE){
logger.error("Le TicketStatut existe déjà ! id="+ pTicketStatut.getId(),pE);
}
}
Hovering over logger shows "Cannot resolve symbol 'logger'
Thanks for your help.
Recommend using sl4j
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Then instantiate:
//generic way to declare logger to be able to copy/paste to other classes
//without changing the class name
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
In dependency, include the binding for sl4j implementation ( can be log4j ).
Can refer here:
logging-with-slf4j
The logger needs to be either instantiated or better injected. It seems that you did not do that. When you use some kind of logging framework like log4j the initialisation would look like this:
static Logger logger = Logger.getLogger(MainApp.class.getName());
When you show us the whole class we can see more details and can guess better.
An tutorial for log4j and spring can be found here.
Indeed, I didn't managed properly my imports:
I added:
private final Log logger = LogFactory.getLog(TicketDaoImpl.class);
from
org.apache.commons.logging.Log;
Stupid lack of attention.
I am having a look also at the doc from log4j/ sl4j on Baeldung. Thanks ^^
Android Studio 0.8.1
java version "1.7.0_60"
Hello,
I have created a jar file and calling this from my Android App. For testing purposed I want to put some logging in the jar file that will be displayed in the LogCat window.
I have decided to use Java's java.util.logging.Logger class. However, when I run my app with No Filter I cannot see any of my log messages being displayed.
import java.util.logging.ConsoleHandler;
import java.util.logging.SimpleFormatter;
import java.util.logging.Handler;
import java.util.logging.Logger;
import java.util.logging.Level;
public class RequestFactory extends WebServiceRequestFactory {
private static final Logger log = Logger.getLogger("RequestFactory");
public RequestFactory() {
ConsoleHandler consoleHandler = new ConsoleHandler();
log.addHandler(consoleHandler);
consoleHandler.setFormatter(new SimpleFormatter());
log.log(Level.FINE, "LOG: Initialized overloaded constructor");
System.out.println("Initialized overloaded constructor");
}
.....
I have set the above to be displayed in the Console. However, the System.out.println always prints out. However, I don't want to use the System.out.println for displaying logs messages.
If possible I would like to stick to java's logging class.
In the LogCat window I can see the System.out.println(...), but not the log.log(...) one:
I/System.out﹕ Initialized overloaded constructor
Am I doing something wrong here?
Many thanks for any suggestions
The default level for the ConsoleHandler is INFO. The default level for the logger is inherited from its parent. By default, the root logger is usually set to INFO. A FINE log message will not be reported using the default settings. Change the log level of the ConsoleHandler to ALL and change the level of the logger to FINE.
log.setLevel(Level.FINE);
consoleHandler.setLevel(Level.ALL);
Here is my code
package com.my;
import org.apache.log4j.spi.LoggerFactory;
import java.io.*;
import java.util.logging.*;
public class Log {
public static void main(String[] args) {
try{
FileHandler hand = new FileHandler("vk.log");
Logger log = Logger.getLogger("log_file");
log.addHandler(hand);
log.warning("Doing carefully!");
log.info("Doing something ...");
log.severe("Doing strictily ");
System.out.println(log.getName());
}
catch(IOException e){
System.out.println(e)
}
}
}
Your code should work if you delete the superfluous log.getLogger(""); statement and fix the imports.
A couple of comments:
If you have multiple loggers you can selectively turn them on and off. It is conventional to create multiple loggers based on class or package names; e.g.
Logger log = Logger.getLogger(this.getClass());
or
Logger log = Logger.getLogger(SomeClass.class);
You are instantiating and associating the handler programmatically. It is a better idea to put the logging configurations into an XML or properties file, and use one of the configurers to load it and wire up the logging handlers. This allows you ... or the user ... to adjust the logging without modifying your code.
You should probably READ the log4j introduction document that explains the above and other things about using log4j.
The above assumes that you were trying to use log4j. Is you are really trying to use java.util.logging, some details are not exactly right. (And, IMO, you would be better off with using log4j or one of its offspring.)
Your code is more or less fine (check the imports) and should work correctly if you remove the line:
log.getLogger("");
A working implementation of your class would then be:
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
public class test {
public static void main(String[] args) {
try {
FileHandler hand = new FileHandler("vk.log");
Logger log = Logger.getLogger("log_file");
log.addHandler(hand);
log.warning("Doing carefully!");
log.info("Doing something ...");
log.severe("Doing strictily ");
System.out.println(log.getName());
} catch (IOException e) {
// Handle error.
}
}
}
Can you explain further your problem?
Here are a couple suggestions.
Watch your imports, you are mixing
Log4j or java.util.logging imports
no need to call getLogger() twice
Do something with your exceptions,
even if that means using a
System.out.println() e.printStackTrace() in this test
case. If there were problems thrown,
you were hiding them.