I'm writing functional tests using Geb and Spock, and building with Maven using GMavenPlus. How can I configure Log4J to to print the line numbers from my Groovy source files? This is my current log4j.properties
log4j.rootLogger=INFO, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-p] %d{dd-MM-yyyy HH:mm:ss} %c:%L - %m%n
Currently this results in messages that look like
[INFO] 2015-07-28 14:13:51,589 Log4jExample:? - Some useful message
This can be reproduced in this small example
#Grab(group='log4j', module='log4j', version='1.2.17')
import org.apache.log4j.*
#groovy.util.logging.Log4j
class Log4jExample {
static void main(def args) {
log.level = Level.INFO
log.removeAllAppenders()
log.addAppender(new ConsoleAppender(new PatternLayout("[%-p] %d %c:%L - %m%n")))
log.info "Some useful message"
}
}
One solutions is to add the #CompileStatic annotation
Your example it would look like
#Grab(group='log4j', module='log4j', version='1.2.17')
import org.apache.log4j.*
#groovy.util.logging.Log4j
#CompileStatic
class Log4jExample {
static void main(def args) {
log.level = Level.INFO
log.removeAllAppenders()
log.addAppender(new ConsoleAppender(new PatternLayout("[%-p] %d %c:%L - %m%n")))
log.info "Some useful message"
}
}
Note that by using #CompileStatic the Groovy meta object protocol will be bypassed.
Related
I've been using HttpBuilder-NG in a large compiled project and relying on its request and response logging when debugging, but using it in a standalone Groovy script results in only output from my class, not the library's logs.
Can anyone suggest how to get those logs I'm expecting to see from the HttpBuilder-NG library being used?
Here's a quick test scenario I put together:
// logging-test.groovy
import ch.qos.logback.classic.Logger
import ch.qos.logback.classic.Level
import static groovyx.net.http.HttpBuilder.configure
import static groovyx.net.http.util.SslUtils.ignoreSslIssues
import groovy.util.logging.Slf4j
import groovyx.net.http.OkHttpBuilder
#GrabConfig(systemClassLoader = true) // Encounters class loading issues without this
#GrabResolver(name = 'mcArtifacts', root = 'https://artifactory.mycompany.com/artifactory/maven-all/')
#Grab(group = 'io.github.http-builder-ng', module = 'http-builder-ng-core', version = '1.0.3')
#Grab(group = 'io.github.http-builder-ng', module = 'http-builder-ng-okhttp', version = '1.0.3')
#Grab('ch.qos.logback:logback-classic:1.2.3')
#Grab('ch.qos.logback:logback-core:1.2.3')
#Slf4j
class LoggingTest {
private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(LoggingTest.class)
static void main(String[] args) {
new LoggingTest().run(args)
}
def run(String[] args) {
def builder = OkHttpBuilder.configure({
ignoreSslIssues execution
request.uri = "https://dummy.restapiexample.com"
})
def currentContents = builder.get {
request.uri.path = "/api/v1/employees"
}
LOGGER.info "Testing output - HttpBuilder-NG gives back a ${currentContents.getClass()}"
LOGGER.debug "Validating debug works."
}
}
And for logback configuration:
// logback.groovy
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.ConsoleAppender
appender('CONSOLE', ConsoleAppender) {
encoder(PatternLayoutEncoder) {
pattern = '%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n'
}
}
logger 'groovyx.net.http.JavaHttpBuilder', DEBUG, [ 'CONSOLE' ]
logger 'groovy.net.http.JavaHttpBuilder', DEBUG, [ 'CONSOLE' ]
logger 'groovy.net.http.JavaHttpBuilder.content', TRACE, [ 'CONSOLE' ]
logger 'groovy.net.http.JavaHttpBuilder.headers', DEBUG, [ 'CONSOLE' ]
root DEBUG, ['CONSOLE']
Console output on execution:
$ groovy logging-test.groovy
08:57:46.053 [main] INFO LoggingTest - Testing output - HttpBuilder-NG gives back a class org.apache.groovy.json.internal.LazyMap
08:57:46.056 [main] DEBUG LoggingTest - Validating debug works.
I have requirement to retain logs for last 50 days only (i only want logs for last 50 days only). in the log4j properties file i have maxbackup index set it to 1 for testing purposes. i am aware that log4j dailyrollingfileappender only rollover monthly yearly daily etc.
But my requirement is to roll over every day but only want for last 50 days, rest to be deleted.
So i have found CustomAppender which extends which extends daily rollingfileappender and my customappender looks as below. Basically we have added maxbackupindex to daily rollingfile appender.
Code:
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.helpers.LogLog;
public class CustomAppender extends DailyRollingFileAppender {
private int maxBackupIndex;
public void setMaxBackupIndex(int maxBackupIndex) {
this.maxBackupIndex = maxBackupIndex;
}
#Override
public void rollOver() throws IOException {
super.rollOver();
File file = new File(fileName);
List<String> files = new ArrayList<>();
File[] dirFiles = new File(file.getAbsolutePath()).getParentFile().listFiles();
if (dirFiles != null && dirFiles.length > 0) {
Arrays.sort(dirFiles, (a, b) -> Long.compare(a.lastModified(), b.lastModified()));
for (File allFile : dirFiles) {
if (allFile.getName().contains(fileName)) {
files.add(allFile.getAbsolutePath());
}
}
}
if (files.size() > maxBackupIndex+1) {
File deleteFile = new File(files.get(0));
LogLog.debug("delete result for"+deleteFile.getAbsolutePath()+" is "+deleteFile.delete());
files.remove(0);
}
}
}
my log4j properties looks below.
log4j.rootLogger=WARN,stdout
log4j.logger.X.Y.Z.A=DEBUG,Application
log4j.appender.Application=org.apache.log4j.CustomAppender
log4j.appender.Application.File=/h/i/logs/m/Application.log
log4j.appender.Application.MaxBackupIndex=1
log4j.appender.Application.layout=org.apache.log4j.PatternLayout
log4j.appender.Application.layout.ConversionPattern=%d{DATE} %-5p %m - %c [%t] [%r ms]%n%n
#set up the apache appender
log4j.logger.org.apache=ON
# Hibernate loggers and appender
#log4j.logger.org.hibernate=DEBUG,Hibernate
log4j.logger.org.hibernate=DEBUG,Hibernate
log4j.additivity.org.hibernate=false
log4j.logger.org.hibernate.SQL=DEBUG,Hibernate
log4j.additivity.org.hibernate.SQL=false
log4j.logger.org.hibernate.type=DEBUG,Hibernate
log4j.additivity.org.hibernate.type=false
log4j.appender.Hibernate=org.apache.log4j.CustomAppender
log4j.appender.Hibernate.File=/h/i/logs/m/Hibernate.log
log4j.appender.Hibernate.MaxBackupIndex=1
log4j.appender.Hibernate.layout=org.apache.log4j.PatternLayout
log4j.appender.Hibernate.layout.ConversionPattern=Hib: %d [%t] %-5p %c - %m%n%n
However, the previous files are not being deleted , even though maxbackupindex is set to 1.
any one can please help me out?
i'm actually trying to run a keyword from imported test library written in java (RF 3.0.2 , Jython 2.7.1rc3 )
import org.apache.log4j.Logger;
public class Sample
{
private static final Logger logger = Utils.getLogger(Sample.class);
#RobotKeyword("Print Message")
#ArgumentNames({"message"})
public void printMessage(String message)
{
logger.info("I'm inside");
}
}
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
public class Utils
{
public static final Logger logger = getLogger(Utils.class);
public static Logger getLogger(Class<?> clazz)
Logger logger = Logger.getLogger(className.getClass());
PropertyConfigurator.configure("/src/main/resources/log4j.properties");
return logger;
}
log4j.properties :
log4j.rootLogger=DEBUG, Stdout, file
log4j.appender.Stdout=org.apache.log4j.ConsoleAppender
log4j.appender.Stdout.Target=System.out
log4j.appender.Stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.Stdout.layout.conversionPattern=%d %-5p [%t] %F:%L %m%n
log4j.appender.Stdout.ImmediateFlush=true
log4j.appender.Stdout.follow=true
With this setup i'm able to see log after test execution in robot framework test report but it would be very helpful if i can see logs during test execution as if i was calling log to console keyword.
is There a way to do this ?
You can use listener interface http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface to get real time execution information. In docs there is a sample script.
This is used in RED Robot Editor to get execution status,debug information etc. - source can be found:
TestRunnerAgent.py
log4j.properties
log4j.rootLogger=ON, A1
log4j.logger.org.apache.jsp=DEBUG
log4j.appender.A1=org.apache.log4j.FileAppender
log4j.appender.A1.File=test.log
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] - %m%n
test.java
package ch15;
import org.apache.log4j.Logger;
public class test
{
static Logger logger = Logger.getLogger(test.class);
public static void main(String[] args)
{
makeLog();
}
public static String makeLog()
{
logger.debug("test");
return "YES";
}
}
When I compile this java file and execute, Log File created Normally.
[2013-05-10 16:53:24] - test
But when I intend to use this class file in JSP like below, there's no Log at all.
<jsp:useBean id="t" class="ch15.test" />
<%=t.makeLog()%>
I think JSP call test class successfully because browser displays "YES".
But no log written...
Can you help me?
I'm in trouble for a week...:(
In my project I've got a top-level abstract class FrameProducer. I added a slf4j logger at this level, so that every inheriting class already has it. Here the code:
public abstract class FrameProducer extends Observable {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
protected BufferedImage frame;
public BufferedImage getFrame() {
return frame;
}
public void fireEvent() {
logger.debug("Firing event. Implementing class: {}", this.getClass());
setChanged();
notifyObservers();
}
}
There are also two inheriting classes: CameraFrameGrabber and GrayscaleFilter. Yet, when the method fireEvent() is being called from CameraFrameGrabber or GrayscaleFilter the message is being logged at FrameProducer level. Here the log, for clarity:
FrameProducer.fireEvent - Firing event. Implementing class: class com.ofj.frameaccess.CameraFrameGrabber
FrameProducer.fireEvent - Firing event. Implementing class: class com.ofj.frameaccess.GrayscaleFilter
Is it possible to initialize the logger in FrameProducer in a way that everything gets logged at the most-specialized level in my class hierarchy?
Thanks for any help.
Edit: My log4j.properties looks like this:
log4j.rootCategory=TRACE, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%C{1}.%M - %m%n
Logging in abstract classes is considered an anti-pattern by some because it introduces a potentially unexpected dependency. However if you are sure that all the stuff you are dealing with is your own that that's no problem I guess.
If you want to get the log message to show the concrete implementation rather than the abstract class name (which makes sense) then change your logging initialization statement in the abstract class to:
private final Logger logger = LoggerFactory.getLogger(getClass());
instead of something like:
private static final Logger logger = LoggerFactory.getLogger(MyAbstractClass.class);
i.e.
no static because it could be cast to something else.
getClass() instead of the specific class
Thanks for pointing out the right direction to look for possible corrections skaffman. I eventually changed my log4j.properties to (as one of the examples in the PatternLayout documentation says):
log4j.rootCategory=TRACE, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%-6r [%15.15t] %-5p %30.30c %x - %m%n
...and everything gets logged right.