Lombok not working in springboot application - java

I want to bean or inject logger so that I don't end up creating an object of logger in each and every class.
So I am trying to integrate Lombok which would help me to resolve lot of things including logger.
Here is my code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#SpringBootApplication
public class MyApplication {
private static final Logger logger = LoggerFactory.getLogger(MyApplication.class);
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
log.debug("Hello");
logger.info("Info log", MyApplication.class.getSimpleName());
}
}
But this is giving me error when I try to use log directly
IDE error -
log cannot be resolved
Console runtime error -
Exception in thread "main" java.lang.NullPointerException: Cannot
invoke "org.slf4j.Logger.info(String, Object)" because
"com.MyApplication .log" is null at
com.MyApplication.main(MyApplication .java:27)
Pom.xml
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.4.5</version>
</dependency>
I have also installed lomback to my Eclipse IDE

Looks like you didn't install the Lombok plugin in your IDE.
Take a look at https://projectlombok.org/setup/overview under IDEs. There you can find instructions on how to install the plugin on most common used IDEs.
Also try to remove the logger from your code. This line:
private static final Logger logger = LoggerFactory.getLogger(MyApplication.class);
Because this is what lombok is adding at compile time. And you don't need the logging dependency because it's already part of spring-boot

Related

Unable to send the logs to Splunk Enterprise local using log4j2

I'm using log4j2 and splunk within java to send logs into my Splunk Enterprise HEC (HTTP Event Collector) Splunk Enterprise is running in my local machine.
I'm doing all log4j2 configuration programmatically. (I know this is not the correct way to do this but I'm still doing this for learning purpose).
I tried to send the logs into Splunk Enterprise directly from postman with the same URL and token and it works fine, but when I tried to send the logs from java using log4j2 I don't get anything in splunk.
My code is =>
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.layout.PatternLayout;
import com.splunk.logging.*;
public class Main {
private static final Logger log;
static {
configureLog4J();
log = LogManager.getLogger(Main.class);
}
public static void configureLog4J() {
ConfigurationBuilder<BuiltConfiguration> builder =
ConfigurationBuilderFactory.newConfigurationBuilder();
// configure a splunk appender
builder.add(
builder.newAppender("splunkH", "SplunkHttp")
.add(
builder.newLayout(PatternLayout.class.getSimpleName())
.addAttribute(
"pattern",
"%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
)
)
.addAttribute("sourcetype", "log4j2")
.addAttribute("index", "main")
.addAttribute("url", "http://localhost:8088/services/collector") //I tried this url in postman and its working fine there
.addAttribute("token", "xxx")
.addAttribute("disableCertificateValidation", "true")
);
// configure the root logger
builder.add(
builder.newRootLogger(Level.INFO)
.add(builder.newAppenderRef("splunkH"))
);
// apply the configuration
Configurator.initialize(builder.build());
}//end of configureLog4J
public static void main(String ar[]) {
log.log(Level.INFO, "Hello from log4j2");
log.log(Level.ERROR, "Error from log4j2");
}//end of main method
}//end of class
my POM file
<dependencies>
<dependency>
<groupId>com.splunk.logging</groupId>
<artifactId>splunk-library-javalogging</artifactId>
<version>1.11.4</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>com.splunk</groupId>
<artifactId>splunk</artifactId>
<version>1.6.5.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>splunk-artifactory</id>
<name>Splunk Releases</name>
<url>https://splunk.jfrog.io/splunk/ext-releases-local</url>
</repository>
</repositories>
I cannot see any logs in splunk. Did I miss something ?
Add .addAttribute("batch_size_count", "1") or make a loop producing 10 log messages, becasue that's the default value of batch_size_count. This has been explained in splunk docs "Configure Log4j 2" section.
By the way, I reckon the services/collector endpoint should be used with JSON messages (e.g. .add(builder.newLayout("JSONLayout"))). Also, you are using a log4j2 version that has the Log4Shell (CVE-2021-44228) vulnerability. It has been fixed in 2.15.0, switch to anything between that and the newest version 2.17.2.
Finally, I share the sentiment of the answers to the question How to configure log4j 2.x purely programmatically? that log4j2 is troublesome to use when configured programmatically. I had issues with it in a cluster env and switching to file configuration solved all my problems.

How to use custom logger with Logback and SLF4J

I have existing project with very standart Logback implementation.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class SomeClass{
Logger log = LoggerFactory.getLogger(getClass());
void someMethod(){
log.info("some log message");
}
}
This is used in many places and in code I dont have sources. ch.qos.logback.classic.Logger is used as implementation.
I want to use my own implementation of Logger (I wanted to extend ch.qos.logback.classic.Logger but it's final) and use it applicatio wide without modifying the code (which I don't have anyway).
I would expect that configuration of LoggerFactory in logback.xml would be possible, but it doesn't seem so.
I'm using maven artifacts
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
I could not find straight way of doing it. I came over XLogger and logback-ext but it seems I would need to modify all factory usages.

Test class in spring dosn't work properly

I would like to test my controller class. But I couldn't manage to run springBootTest class. My project written in spring boot. We are writing REST API using spring boot.
When I try to excute following test class. I still get following line from terminal.
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
/*
*
* #A Sabirov Jakhongir
*
*/
#SpringBootTest
#WebMvcTest
public class PrivilegesControllerTest {
#Autowired
private PrivilegesController privilegesController;
#Test
public void add() {
assertThat(privilegesController).isNotNull();
}
}
I put here all needed dependency for testing from my project.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-launcher -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
What might be cause of not working of test Class.
With Junit5 and #SpringBootTest will load the full application, I had faced the same issue before, you can find details about the question here and answer here.
The solution for this is to use your test without #SpringBootTest.
The solution to your test class is as below.
#ExtendWith(MockitoExtension.class)
public class PrivilegesControllerTest {
#InjectMocks
private PrivilegesController privilegesController;
#Test
public void add() {
assertThat(privilegesController).isNotNull();
}
}
You can also use #ExtendWith(SpringExtension.class) instead of #ExtendWith(MockitoExtension.class)
To test spring boot application is creating your controller, use #SpringBootTest annotation, and to test the behavior or responsibility of the controller is better to use #WebMvcTest. No need to annotate both the annotation to one class.
There are two cases to test the controller's responsibility.
With running Server
Without Server
For 1st Case, you can use #SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) to start a server with a random port.
For 2nd Case, use #WebMvcTest for testing the web layer.
All the test cases are written with the following signature:
#Test
public void test_Name() throws Exception {
//your test definition
}
You can also read the Official Documentation of Spring Boot https://spring.io/guides/gs/testing-web/

Java hadoop api YarnClient doesn't have "init()/start()" function?

I tried maven repo like this:
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-yarn-common</artifactId>
<version>2.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-yarn-api -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-yarn-api</artifactId>
<version>2.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-yarn-client -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-yarn-client</artifactId>
<version>2.7.2</version>
</dependency>
Then my java code:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.ApplicationConstants;
import org.apache.hadoop.yarn.api.records.*;
import org.apache.hadoop.yarn.client.api.YarnClient;
import org.apache.hadoop.yarn.client.api.YarnClientApplication;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.exceptions.YarnException;
public static void main(String[] args) {
YarnConfiguration yarnConfiguration = new YarnConfiguration();
YarnClient yarnClient = YarnClient.createYarnClient();
yarnClient.init(yarnConfiguration);
yarnClient.start();
}
Intellij ide shows "Cannot solve method init" and "Cannot solve method start".
I then tried to use jar version of 3.1.1 instead of "2.7.2". Same result. So what's wrong with my code and how to fix it?
the init and start method are derived from the AbstractService class.
you need to verify the YarnClient and AbstractService has the same version.
go to YarnClient and check the jar it refer to, then click on the AbstractService parent from the Yarn client and check his version.
change the YarnClient version according to your AbstractService version.
i had the same issue, it works for me . version 2.6.5 .

How to make OpenEJB to use slf4j?

Can anyone give an example of pom.xml dependencies configuration that will make OpenEJB to use slf4j logging, instead of JCL (this is what it uses now, as I understand).
see also How to configure OpenEJB logging?
We have support for:
Log4j
java.uti.logging
New implementations of LogStreamFactory can be plugged in by setting the class name as the value of openejb.log.factory system property.
Feel free to copy one of the existing impls and update for either JCL or SLF4J. The project is always accepting new committers if you get the urge to hack on other things as well!
Thanks to David's pointers, this is actually quite easy. You only need to implement two clases:
- Slf4jLogStreamFactory
- Slf4jLogStream
then set your factory :
System.setProperty("openejb.log.factory", "de.glauche.Slf4jLogStreamFactory");
package de.glauche;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.LogStream;
import org.apache.openejb.util.LogStreamFactory;
public class Slf4jLogStreamFactory implements LogStreamFactory {
#Override
public LogStream createLogStream(LogCategory logCategory) {
return new Slf4jLogStream(logCategory);
}
}
and the Slf4jLogStream:
package de.glauche;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.LogStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Slf4jLogStream implements LogStream {
private Logger log;
public Slf4jLogStream(LogCategory logCategory) {
log = LoggerFactory.getLogger(logCategory.getName());
}
#Override
public boolean isFatalEnabled() {
return log.isErrorEnabled();
}
#Override
public void fatal(String message) {
log.error(message);
}
#Override
public void fatal(String message, Throwable t) {
log.error(message,t);
}
... (overwrite the remaining methods like this)
With this i'm getting all output nicely formated in my logback logger via slf4j :)
This is how I made OpenEJB to use external logging:
[...]
#Before
public void before() throws Exception {
System.setProperty("openejb.logger.external", "true");
InitialContext ctx = new InitialContext();
}
[...]
Maybe it's possible to move this system property to some global resource, like pom.xml?
If you add the API and JCL dependencies then your logging using the SLF4J API will get directed to the default JCL logs.
Is that what you want? Or do you want to use some other back end for the logging?
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jcl</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
Not a Maven expert, but from my understanding, you want this:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.6.1</version>
</dependency>
If OpenEJB doesn't support JCL, it would be pointless to add that dependency, so go with JUL or Log4j.
You can find more details at Maven repository.
Just in case you really want to use JCL bridge, use this:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.6.1</version>
</dependency>
If you are executing via Maven's exec plugin, try this:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>your Mainclass here</mainClass>
<systemProperties>
<systemProperty>
<key>openejb.log.factory</key>
<value>slf4j</value>
</systemProperty>
</systemProperties>
</configuration>
</plugin>

Categories