How to make logging components visible across whole Spring Boot application - spring

I'm running Spring Boot and I want to add logging to my application. All examples have the following for the main Application entrypoint:
private static final Logger log = LoggerFactory.getLogger(Application.class);
However, I want the same log variable visible (as Singleton) across all my application components (services, controllers, etc.). How would I do that? Thanks!

You can use springs IoC container to achieve this.
just configure a bean like this in a #Configuration cass
#Bean
public Logger log() {
return LoggerFactory.getLogger(AnyClassYouWant.class);
}
and inject it with #Autowired in your class
class WhatEver {
#Autowired
Logger log;
//...
}

You can create a static class.. Which contain:
private static final Logger log = LoggerFactory.getLogger(StaticLog.class);
And will expose methods to write logs..
Hope that answer your needs

Related

Get SLF4J loggers for given package

For my current application, I am attempting to get the loggers for the given package. However, after multiple attempts still I am unable to do that. I will add the sample code block for what I've been trying so far.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final Logger logger;
private TestUtils(String thePackageOrLoggerName) {
ILoggerFactory iLoggerFactory = LoggerFactory.getILoggerFactory();
this.logger = iLoggerFactory.getLogger(thePackageOrLoggerName);
}
However, the logger I get from the above code does not work. It has the name attribute with the package I've given but it doesn't contain any loggers within the package. In the above example I am only based on SLF4J and does not relay on Log4j2 or Logback because I want this implementation to be independent of underlying logging framework.
However, I could accomplish what I want to do in my previous attempt but I did use logback-core library. I will also add the code block for that as well for a better understanding of what I am going to do.
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
private final Logger logger;
private testUtils(String thePackageOrLoggerName) {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
this.logger = context.getLogger(thePackageOrLoggerName);
}
With the above implementation, my logger contains all the logger instances for the given package. I want to accomplish the same behaviour without using the logback-core and only using SLF4J related libraries. Can anyone give me insights to proceed further and it is much appreciated.
Try using lombok instead and add #Slf4j above the class.
Now you can do like:
LOGGER.info("Text");
LOGGER.getName();
LOGGER...{etc}
Will make things super easy. You just need to add #Slf4j above any class you want a logger in. And it will do the rest for you.
If you only wanted a single logger. You can make a single logger class this way. And just create methods to call the logger inside the class
#Slf4j
#NoArgsConstructor
#Component
public class TestLogger() {
public void logWarning(String warn){
LOGGER.warn(warn);
}
public void logError(String error){
LOGGER.error(error);
}
}
Then just Autowire this class into each area you need it.
All code is untested and was written in the text field provided here.
https://mvnrepository.com/artifact/org.projectlombok/lombok

Inject/Access Spring Bean into Log4j2 Plugin

I have a configuration properties class that I want to inject into a custom log4j2 RewritePolicy.
e.g.
#Plugin(name = "MyPolicy", category = "Core", elementType = "rewritePolicy", printObject = true)
public class MyPolicy implements RewritePolicy {
private MyPolicyProperties myPolicyProperties; // <-- want to inject/autowire this
public MyPolicy() {}
#PluginFactory
public static MyPolicy createPolicy() {
return new MyPolicy();
}
#Override
public LogEvent rewrite(LogEvent logEvent) {
// do something with myPolicyProperties here
return Log4jLogEvent.newBuilder()
.setLoggerName(logEvent.getLoggerName())
.setMarker(logEvent.getMarker())
.setLoggerFqcn(logEvent.getLoggerFqcn())
// ... etc
.build();
}
}
#ConfigurationProperties("app.mypolicy")
#Getter
#Setter
public class MyPolicyProperties {
private String property1;
private int property2;
// ... etc
}
I've tried implementing an ApplicationListener to reconfigure log4j as described here but was can't seem to get the appender and/or rewritepolicy to configure. Also tried implementing ApplicationContextAware described here but also didn't work.
Is there anyway to access the MyPolicyProperties in MyPolicy?
It can be done but it is almost never pretty. This is because Log4j Plugins are loaded by Log4j's plugin system while Spring Beans are loaded by Spring. Furthermore, they are not instantiated at the same time.
If you are using Spring Boot the very first thing that will happen is for Log4j2 to initialize because SpringApplication requests a Logger. So there would be no way to resolve the Spring Bean at that point as it doesn't exist. Later, Spring's bootstrap process will initialize Log4j again and then during application setup it will initialize once or twice more. During these subsequent initializations the bean may be available.
Depending on the type of application you are using you may be able to locate Spring's ApplicationContext so that you can call getBean() and inject it.
There is no automatic way to do this via an annotation or something similar.
The simplest way to do it is to either add a static method in the target class that gets initialized to reference itself when Spring is initialized or to create another class with a method that initializes a static method to reference the Spring created bean. So Spring will cause these static methods to reference the bean it creates. Then have your Log4j plugin call that static method to get the bean reference. Once it is non-null you can save it in the plugin and after that it should function as you want.

How to execute part of the code on Quarkus when starting the application?

Please help me understand that how to execute part of the code on Quarkus when starting the application?
If possible, discard the link or give an example code.
Thanks.
Not sure to understand your question but if you want to execute code at startup, the easiest way is to observe (using #Observes) the StartupEvent with a CDI bean:
#ApplicationScoped
public class AppLifecycleBean {
private static final Logger LOGGER = Logger.getLogger("ListenerBean");
void onStart(#Observes StartupEvent ev) {
LOGGER.info("The application is starting...");
}
void onStop(#Observes ShutdownEvent ev) {
LOGGER.info("The application is stopping...");
}
}
You can find more details in our documentation if you need a better understanding of the Quarkus application lifecycle:
https://quarkus.io/guides/lifecycle#listening-for-startup-and-shutdown-events
There is an #Startup annotation for Quarkus that will instantiate a service upon startup. It simply automates the listening of the StartupEvent:
For each bean annotated with #Startup a synthetic observer of StartupEvent is generated. The default priority is used.
Works well.
Quarkus #Startup annotation

How to use application.properties in org.quartz.Job Class

I have created a spring boot application to implement Quartz scheduler. In Job class, I want to use some property from application.properties. How to inject that?
I have tried below but getting null:
#Component
public class ScheduleJob implements org.quartz.Job {
private static final Logger LOGGER = LogManager.getLogger(ScheduleJob.class);
public ScheduleJob() {
}
#Value("${ijobs.service.url}")
private String ijobsUrl;
public void execute(JobExecutionContext context) throws JobExecutionException {
LOGGER.info("Job exceution starts--->");
System.out.println("-------------------"+ijobsUrl);
Spring requires annotating the class with #Component for it to manage it (including loading any properties into the class). If you use "new" to create the object, then it is outside Spring's control and it won't inject the dependencies/values into it.
On side note, there is native support for Quartz if using Spring Boot: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-quartz.html
Firstly, the ScheduleJob class should be annotated with #Component for spring to manage it. Secondly, if you want any property to be injected you could do it in a similar way to how you are injecting value of ijobsUrl.
put your required property in application.properties
#Value("${my.property}")
private String myProperty

In Spring how do I configure java.util.Logging so it can be autowired?

In our webapp we're using java.util.Logging (JULI, actually, since we deploy to Tomcat 6). Logging is configured by a logging.properties file in WEB-INF/classes, a la this.
I'd like to configure the logger so it can be autowired, something like:
#Autowired
private Logger mylogger;
I've searched the Spring forums, the web, and of course Stack Overflow and I can't find how to set this up. I'd appreciate any help on this.
Thanks!
One way would be to use the Java Config style, so you'd have one bean like this:
#Configuration
public class LoggerProvider {
#Bean
public Logger logger() {
return Logger.getLogger("foobar.whatever");
}
}
That could then be autowired into the rest of the app as normal.
In order to use #Autowired on something (a bean) you must make that bean spring-controlled. There are many ways to do this and they depend on the logging framework you want to use.
I'm afraid there isn't a 'one-size-fits-all' solution.
Usually, you would use a static initializer provided by the logging framework of your choice or some abstraction over it (e.g. commons-logging).
I found one reference in which a #Logger annotation is introduced, maybe that points you into a direction of your liking:
http://jgeeks.blogspot.com/2008/10/auto-injection-of-logger-into-spring.html
In order to make Logger be injectable with #Autowired, you must have a configuration class where you have configured all the Beans with which you use #Autowired. That class will be marked with #Configuration. There you must put the following #Bean in your configuration:
#Configuration
public class WebConfiguration {
#Bean
#Scope("prototype")
public Logger produceLogger(InjectionPoint injectionPoint) {
Class<?> classOnWired = injectionPoint.getMember().getDeclaringClass();
return LoggerFactory.getLogger(classOnWired);
}
}

Resources