Change appender level instead of the logger level
My team uses Spring Boot Admin
for controlling our spring application
,
In Spring Boot Admin
we have the option to change the logger
level in Runtime
,
we have a separate logger for each task
(Thread), and if we want to see the console logs only for one thread we turning off all the other threads loggers,
The problem is that each logger sends it's output both for the STDOUT
and also for a certain file, and we want to turn off only the stdout output.
log4j2.xml configuration example:
<Loggers>
<Logger name="task1" level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
<Logger name="task2" level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
</Loggers>
we tried a lot of solutions:
- use parent loggers combined with additivity, and separate each appender to different logger,
Any ideas about it?
spring-boot log4j2 spring-boot-admin
add a comment |
My team uses Spring Boot Admin
for controlling our spring application
,
In Spring Boot Admin
we have the option to change the logger
level in Runtime
,
we have a separate logger for each task
(Thread), and if we want to see the console logs only for one thread we turning off all the other threads loggers,
The problem is that each logger sends it's output both for the STDOUT
and also for a certain file, and we want to turn off only the stdout output.
log4j2.xml configuration example:
<Loggers>
<Logger name="task1" level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
<Logger name="task2" level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
</Loggers>
we tried a lot of solutions:
- use parent loggers combined with additivity, and separate each appender to different logger,
Any ideas about it?
spring-boot log4j2 spring-boot-admin
Are you able to add a separate Logger for console and File appender? Like : <Logger name="task1Console" level="info"> <AppenderRef ref="Console"/> <AppenderRef ref="File"/> </Logger> <Logger name="task1File" level="info"> <AppenderRef ref="File"/> </Logger>
– don
Jan 7 at 7:13
Can you add code related with task/thread?
– Jonathan Johx
Jan 8 at 3:35
add a comment |
My team uses Spring Boot Admin
for controlling our spring application
,
In Spring Boot Admin
we have the option to change the logger
level in Runtime
,
we have a separate logger for each task
(Thread), and if we want to see the console logs only for one thread we turning off all the other threads loggers,
The problem is that each logger sends it's output both for the STDOUT
and also for a certain file, and we want to turn off only the stdout output.
log4j2.xml configuration example:
<Loggers>
<Logger name="task1" level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
<Logger name="task2" level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
</Loggers>
we tried a lot of solutions:
- use parent loggers combined with additivity, and separate each appender to different logger,
Any ideas about it?
spring-boot log4j2 spring-boot-admin
My team uses Spring Boot Admin
for controlling our spring application
,
In Spring Boot Admin
we have the option to change the logger
level in Runtime
,
we have a separate logger for each task
(Thread), and if we want to see the console logs only for one thread we turning off all the other threads loggers,
The problem is that each logger sends it's output both for the STDOUT
and also for a certain file, and we want to turn off only the stdout output.
log4j2.xml configuration example:
<Loggers>
<Logger name="task1" level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
<Logger name="task2" level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
</Loggers>
we tried a lot of solutions:
- use parent loggers combined with additivity, and separate each appender to different logger,
Any ideas about it?
spring-boot log4j2 spring-boot-admin
spring-boot log4j2 spring-boot-admin
asked Jan 1 at 7:18


Daniel TaubDaniel Taub
1,62521939
1,62521939
Are you able to add a separate Logger for console and File appender? Like : <Logger name="task1Console" level="info"> <AppenderRef ref="Console"/> <AppenderRef ref="File"/> </Logger> <Logger name="task1File" level="info"> <AppenderRef ref="File"/> </Logger>
– don
Jan 7 at 7:13
Can you add code related with task/thread?
– Jonathan Johx
Jan 8 at 3:35
add a comment |
Are you able to add a separate Logger for console and File appender? Like : <Logger name="task1Console" level="info"> <AppenderRef ref="Console"/> <AppenderRef ref="File"/> </Logger> <Logger name="task1File" level="info"> <AppenderRef ref="File"/> </Logger>
– don
Jan 7 at 7:13
Can you add code related with task/thread?
– Jonathan Johx
Jan 8 at 3:35
Are you able to add a separate Logger for console and File appender? Like : <Logger name="task1Console" level="info"> <AppenderRef ref="Console"/> <AppenderRef ref="File"/> </Logger> <Logger name="task1File" level="info"> <AppenderRef ref="File"/> </Logger>
– don
Jan 7 at 7:13
Are you able to add a separate Logger for console and File appender? Like : <Logger name="task1Console" level="info"> <AppenderRef ref="Console"/> <AppenderRef ref="File"/> </Logger> <Logger name="task1File" level="info"> <AppenderRef ref="File"/> </Logger>
– don
Jan 7 at 7:13
Can you add code related with task/thread?
– Jonathan Johx
Jan 8 at 3:35
Can you add code related with task/thread?
– Jonathan Johx
Jan 8 at 3:35
add a comment |
1 Answer
1
active
oldest
votes
Log4j2 does not allow to manage System.out and System.err streams by default.
To clarify how console logger works:
Simply Console
appender prints its output to System.out or System.err. According to documentation, if you do not specify target by default it will print to System.out:
https://logging.apache.org/log4j/2.x/manual/appenders.html
target || String || Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_OUT".
Here is an example:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<Properties>
<Property name="log-pattern">%d{ISO8601} %-5p %mn</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
</Console>
</appenders>
<Loggers>
<logger name="testLogger" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
</Loggers>
</configuration>
LogApp.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogApp {
public static void main(String args) {
Logger log = LogManager.getLogger("testLogger");
log.info("Logger output test!");
System.out.println("System out test!");
}
}
Output:
2019-01-08T19:08:57,587 INFO Logger output test!
System out test!
A Workaround To Manage System Streams
Take Dmitry Pavlenko's stream redirection class
https://sysgears.com/articles/how-to-redirect-stdout-and-stderr-writing-to-a-log4j-appender/
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.OutputStream;
/**
* A change was made on the existing code:
* - At (LoggingOutputStream#flush) method 'count' could contain
* single space character, this types of logs has been skipped
*/
public class LoggingOutputStream extends OutputStream {
private static final int DEFAULT_BUFFER_LENGTH = 2048;
private boolean hasBeenClosed = false;
private byte buf;
private int count;
private int curBufLength;
private Logger log;
private Level level;
public LoggingOutputStream(final Logger log,
final Level level)
throws IllegalArgumentException {
if (log == null || level == null) {
throw new IllegalArgumentException(
"Logger or log level must be not null");
}
this.log = log;
this.level = level;
curBufLength = DEFAULT_BUFFER_LENGTH;
buf = new byte[curBufLength];
count = 0;
}
public void write(final int b) throws IOException {
if (hasBeenClosed) {
throw new IOException("The stream has been closed.");
}
// don't log nulls
if (b == 0) {
return;
}
// would this be writing past the buffer?
if (count == curBufLength) {
// grow the buffer
final int newBufLength = curBufLength +
DEFAULT_BUFFER_LENGTH;
final byte newBuf = new byte[newBufLength];
System.arraycopy(buf, 0, newBuf, 0, curBufLength);
buf = newBuf;
curBufLength = newBufLength;
}
buf[count] = (byte) b;
count++;
}
public void flush() {
if (count <= 1) {
count = 0;
return;
}
final byte bytes = new byte[count];
System.arraycopy(buf, 0, bytes, 0, count);
String str = new String(bytes);
log.log(level, str);
count = 0;
}
public void close() {
flush();
hasBeenClosed = true;
}
}
And create a custom logger for system output stream, than register it.
Here is the complete code of the logger usage:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<Properties>
<Property name="log-pattern">%d{ISO8601} %-5p %mn</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
</Console>
</appenders>
<Loggers>
<logger name="testLogger" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
<logger name="systemOut" level="info" additivity="true"/>
</Loggers>
</configuration>
SystemLogging.java
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import java.io.PrintStream;
public class SystemLogging {
public void enableOutStreamLogging() {
System.setOut(createPrintStream("systemOut", Level.INFO));
}
private PrintStream createPrintStream(String name, Level level) {
return new PrintStream(new LoggingOutputStream(LogManager.getLogger(name), level), true);
}
}
LogApp.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogApp {
public static void main(String args) {
new SystemLogging().enableOutStreamLogging();
Logger log = LogManager.getLogger("testLogger");
log.info("Logger output test!");
System.out.println("System out test!");
}
}
Final output
2019-01-08T19:30:43,456 INFO Logger output test!
19:30:43.457 [main] INFO systemOut - System out test!
Now, customize system out with new logger configuration as you wish.
Plus; if you don't want to override System.out
and just want to save it: there is TeeOutputStream in commons-io library. You can just replace original System.out
with a combination of original System.out
and LoggingOutputStream
that will write simultaniously to both streams. This won't change the original output but allow you to save System.out
with a logging appender.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53993719%2fchange-appender-level-instead-of-the-logger-level%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Log4j2 does not allow to manage System.out and System.err streams by default.
To clarify how console logger works:
Simply Console
appender prints its output to System.out or System.err. According to documentation, if you do not specify target by default it will print to System.out:
https://logging.apache.org/log4j/2.x/manual/appenders.html
target || String || Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_OUT".
Here is an example:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<Properties>
<Property name="log-pattern">%d{ISO8601} %-5p %mn</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
</Console>
</appenders>
<Loggers>
<logger name="testLogger" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
</Loggers>
</configuration>
LogApp.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogApp {
public static void main(String args) {
Logger log = LogManager.getLogger("testLogger");
log.info("Logger output test!");
System.out.println("System out test!");
}
}
Output:
2019-01-08T19:08:57,587 INFO Logger output test!
System out test!
A Workaround To Manage System Streams
Take Dmitry Pavlenko's stream redirection class
https://sysgears.com/articles/how-to-redirect-stdout-and-stderr-writing-to-a-log4j-appender/
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.OutputStream;
/**
* A change was made on the existing code:
* - At (LoggingOutputStream#flush) method 'count' could contain
* single space character, this types of logs has been skipped
*/
public class LoggingOutputStream extends OutputStream {
private static final int DEFAULT_BUFFER_LENGTH = 2048;
private boolean hasBeenClosed = false;
private byte buf;
private int count;
private int curBufLength;
private Logger log;
private Level level;
public LoggingOutputStream(final Logger log,
final Level level)
throws IllegalArgumentException {
if (log == null || level == null) {
throw new IllegalArgumentException(
"Logger or log level must be not null");
}
this.log = log;
this.level = level;
curBufLength = DEFAULT_BUFFER_LENGTH;
buf = new byte[curBufLength];
count = 0;
}
public void write(final int b) throws IOException {
if (hasBeenClosed) {
throw new IOException("The stream has been closed.");
}
// don't log nulls
if (b == 0) {
return;
}
// would this be writing past the buffer?
if (count == curBufLength) {
// grow the buffer
final int newBufLength = curBufLength +
DEFAULT_BUFFER_LENGTH;
final byte newBuf = new byte[newBufLength];
System.arraycopy(buf, 0, newBuf, 0, curBufLength);
buf = newBuf;
curBufLength = newBufLength;
}
buf[count] = (byte) b;
count++;
}
public void flush() {
if (count <= 1) {
count = 0;
return;
}
final byte bytes = new byte[count];
System.arraycopy(buf, 0, bytes, 0, count);
String str = new String(bytes);
log.log(level, str);
count = 0;
}
public void close() {
flush();
hasBeenClosed = true;
}
}
And create a custom logger for system output stream, than register it.
Here is the complete code of the logger usage:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<Properties>
<Property name="log-pattern">%d{ISO8601} %-5p %mn</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
</Console>
</appenders>
<Loggers>
<logger name="testLogger" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
<logger name="systemOut" level="info" additivity="true"/>
</Loggers>
</configuration>
SystemLogging.java
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import java.io.PrintStream;
public class SystemLogging {
public void enableOutStreamLogging() {
System.setOut(createPrintStream("systemOut", Level.INFO));
}
private PrintStream createPrintStream(String name, Level level) {
return new PrintStream(new LoggingOutputStream(LogManager.getLogger(name), level), true);
}
}
LogApp.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogApp {
public static void main(String args) {
new SystemLogging().enableOutStreamLogging();
Logger log = LogManager.getLogger("testLogger");
log.info("Logger output test!");
System.out.println("System out test!");
}
}
Final output
2019-01-08T19:30:43,456 INFO Logger output test!
19:30:43.457 [main] INFO systemOut - System out test!
Now, customize system out with new logger configuration as you wish.
Plus; if you don't want to override System.out
and just want to save it: there is TeeOutputStream in commons-io library. You can just replace original System.out
with a combination of original System.out
and LoggingOutputStream
that will write simultaniously to both streams. This won't change the original output but allow you to save System.out
with a logging appender.
add a comment |
Log4j2 does not allow to manage System.out and System.err streams by default.
To clarify how console logger works:
Simply Console
appender prints its output to System.out or System.err. According to documentation, if you do not specify target by default it will print to System.out:
https://logging.apache.org/log4j/2.x/manual/appenders.html
target || String || Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_OUT".
Here is an example:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<Properties>
<Property name="log-pattern">%d{ISO8601} %-5p %mn</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
</Console>
</appenders>
<Loggers>
<logger name="testLogger" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
</Loggers>
</configuration>
LogApp.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogApp {
public static void main(String args) {
Logger log = LogManager.getLogger("testLogger");
log.info("Logger output test!");
System.out.println("System out test!");
}
}
Output:
2019-01-08T19:08:57,587 INFO Logger output test!
System out test!
A Workaround To Manage System Streams
Take Dmitry Pavlenko's stream redirection class
https://sysgears.com/articles/how-to-redirect-stdout-and-stderr-writing-to-a-log4j-appender/
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.OutputStream;
/**
* A change was made on the existing code:
* - At (LoggingOutputStream#flush) method 'count' could contain
* single space character, this types of logs has been skipped
*/
public class LoggingOutputStream extends OutputStream {
private static final int DEFAULT_BUFFER_LENGTH = 2048;
private boolean hasBeenClosed = false;
private byte buf;
private int count;
private int curBufLength;
private Logger log;
private Level level;
public LoggingOutputStream(final Logger log,
final Level level)
throws IllegalArgumentException {
if (log == null || level == null) {
throw new IllegalArgumentException(
"Logger or log level must be not null");
}
this.log = log;
this.level = level;
curBufLength = DEFAULT_BUFFER_LENGTH;
buf = new byte[curBufLength];
count = 0;
}
public void write(final int b) throws IOException {
if (hasBeenClosed) {
throw new IOException("The stream has been closed.");
}
// don't log nulls
if (b == 0) {
return;
}
// would this be writing past the buffer?
if (count == curBufLength) {
// grow the buffer
final int newBufLength = curBufLength +
DEFAULT_BUFFER_LENGTH;
final byte newBuf = new byte[newBufLength];
System.arraycopy(buf, 0, newBuf, 0, curBufLength);
buf = newBuf;
curBufLength = newBufLength;
}
buf[count] = (byte) b;
count++;
}
public void flush() {
if (count <= 1) {
count = 0;
return;
}
final byte bytes = new byte[count];
System.arraycopy(buf, 0, bytes, 0, count);
String str = new String(bytes);
log.log(level, str);
count = 0;
}
public void close() {
flush();
hasBeenClosed = true;
}
}
And create a custom logger for system output stream, than register it.
Here is the complete code of the logger usage:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<Properties>
<Property name="log-pattern">%d{ISO8601} %-5p %mn</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
</Console>
</appenders>
<Loggers>
<logger name="testLogger" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
<logger name="systemOut" level="info" additivity="true"/>
</Loggers>
</configuration>
SystemLogging.java
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import java.io.PrintStream;
public class SystemLogging {
public void enableOutStreamLogging() {
System.setOut(createPrintStream("systemOut", Level.INFO));
}
private PrintStream createPrintStream(String name, Level level) {
return new PrintStream(new LoggingOutputStream(LogManager.getLogger(name), level), true);
}
}
LogApp.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogApp {
public static void main(String args) {
new SystemLogging().enableOutStreamLogging();
Logger log = LogManager.getLogger("testLogger");
log.info("Logger output test!");
System.out.println("System out test!");
}
}
Final output
2019-01-08T19:30:43,456 INFO Logger output test!
19:30:43.457 [main] INFO systemOut - System out test!
Now, customize system out with new logger configuration as you wish.
Plus; if you don't want to override System.out
and just want to save it: there is TeeOutputStream in commons-io library. You can just replace original System.out
with a combination of original System.out
and LoggingOutputStream
that will write simultaniously to both streams. This won't change the original output but allow you to save System.out
with a logging appender.
add a comment |
Log4j2 does not allow to manage System.out and System.err streams by default.
To clarify how console logger works:
Simply Console
appender prints its output to System.out or System.err. According to documentation, if you do not specify target by default it will print to System.out:
https://logging.apache.org/log4j/2.x/manual/appenders.html
target || String || Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_OUT".
Here is an example:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<Properties>
<Property name="log-pattern">%d{ISO8601} %-5p %mn</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
</Console>
</appenders>
<Loggers>
<logger name="testLogger" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
</Loggers>
</configuration>
LogApp.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogApp {
public static void main(String args) {
Logger log = LogManager.getLogger("testLogger");
log.info("Logger output test!");
System.out.println("System out test!");
}
}
Output:
2019-01-08T19:08:57,587 INFO Logger output test!
System out test!
A Workaround To Manage System Streams
Take Dmitry Pavlenko's stream redirection class
https://sysgears.com/articles/how-to-redirect-stdout-and-stderr-writing-to-a-log4j-appender/
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.OutputStream;
/**
* A change was made on the existing code:
* - At (LoggingOutputStream#flush) method 'count' could contain
* single space character, this types of logs has been skipped
*/
public class LoggingOutputStream extends OutputStream {
private static final int DEFAULT_BUFFER_LENGTH = 2048;
private boolean hasBeenClosed = false;
private byte buf;
private int count;
private int curBufLength;
private Logger log;
private Level level;
public LoggingOutputStream(final Logger log,
final Level level)
throws IllegalArgumentException {
if (log == null || level == null) {
throw new IllegalArgumentException(
"Logger or log level must be not null");
}
this.log = log;
this.level = level;
curBufLength = DEFAULT_BUFFER_LENGTH;
buf = new byte[curBufLength];
count = 0;
}
public void write(final int b) throws IOException {
if (hasBeenClosed) {
throw new IOException("The stream has been closed.");
}
// don't log nulls
if (b == 0) {
return;
}
// would this be writing past the buffer?
if (count == curBufLength) {
// grow the buffer
final int newBufLength = curBufLength +
DEFAULT_BUFFER_LENGTH;
final byte newBuf = new byte[newBufLength];
System.arraycopy(buf, 0, newBuf, 0, curBufLength);
buf = newBuf;
curBufLength = newBufLength;
}
buf[count] = (byte) b;
count++;
}
public void flush() {
if (count <= 1) {
count = 0;
return;
}
final byte bytes = new byte[count];
System.arraycopy(buf, 0, bytes, 0, count);
String str = new String(bytes);
log.log(level, str);
count = 0;
}
public void close() {
flush();
hasBeenClosed = true;
}
}
And create a custom logger for system output stream, than register it.
Here is the complete code of the logger usage:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<Properties>
<Property name="log-pattern">%d{ISO8601} %-5p %mn</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
</Console>
</appenders>
<Loggers>
<logger name="testLogger" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
<logger name="systemOut" level="info" additivity="true"/>
</Loggers>
</configuration>
SystemLogging.java
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import java.io.PrintStream;
public class SystemLogging {
public void enableOutStreamLogging() {
System.setOut(createPrintStream("systemOut", Level.INFO));
}
private PrintStream createPrintStream(String name, Level level) {
return new PrintStream(new LoggingOutputStream(LogManager.getLogger(name), level), true);
}
}
LogApp.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogApp {
public static void main(String args) {
new SystemLogging().enableOutStreamLogging();
Logger log = LogManager.getLogger("testLogger");
log.info("Logger output test!");
System.out.println("System out test!");
}
}
Final output
2019-01-08T19:30:43,456 INFO Logger output test!
19:30:43.457 [main] INFO systemOut - System out test!
Now, customize system out with new logger configuration as you wish.
Plus; if you don't want to override System.out
and just want to save it: there is TeeOutputStream in commons-io library. You can just replace original System.out
with a combination of original System.out
and LoggingOutputStream
that will write simultaniously to both streams. This won't change the original output but allow you to save System.out
with a logging appender.
Log4j2 does not allow to manage System.out and System.err streams by default.
To clarify how console logger works:
Simply Console
appender prints its output to System.out or System.err. According to documentation, if you do not specify target by default it will print to System.out:
https://logging.apache.org/log4j/2.x/manual/appenders.html
target || String || Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_OUT".
Here is an example:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<Properties>
<Property name="log-pattern">%d{ISO8601} %-5p %mn</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
</Console>
</appenders>
<Loggers>
<logger name="testLogger" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
</Loggers>
</configuration>
LogApp.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogApp {
public static void main(String args) {
Logger log = LogManager.getLogger("testLogger");
log.info("Logger output test!");
System.out.println("System out test!");
}
}
Output:
2019-01-08T19:08:57,587 INFO Logger output test!
System out test!
A Workaround To Manage System Streams
Take Dmitry Pavlenko's stream redirection class
https://sysgears.com/articles/how-to-redirect-stdout-and-stderr-writing-to-a-log4j-appender/
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.OutputStream;
/**
* A change was made on the existing code:
* - At (LoggingOutputStream#flush) method 'count' could contain
* single space character, this types of logs has been skipped
*/
public class LoggingOutputStream extends OutputStream {
private static final int DEFAULT_BUFFER_LENGTH = 2048;
private boolean hasBeenClosed = false;
private byte buf;
private int count;
private int curBufLength;
private Logger log;
private Level level;
public LoggingOutputStream(final Logger log,
final Level level)
throws IllegalArgumentException {
if (log == null || level == null) {
throw new IllegalArgumentException(
"Logger or log level must be not null");
}
this.log = log;
this.level = level;
curBufLength = DEFAULT_BUFFER_LENGTH;
buf = new byte[curBufLength];
count = 0;
}
public void write(final int b) throws IOException {
if (hasBeenClosed) {
throw new IOException("The stream has been closed.");
}
// don't log nulls
if (b == 0) {
return;
}
// would this be writing past the buffer?
if (count == curBufLength) {
// grow the buffer
final int newBufLength = curBufLength +
DEFAULT_BUFFER_LENGTH;
final byte newBuf = new byte[newBufLength];
System.arraycopy(buf, 0, newBuf, 0, curBufLength);
buf = newBuf;
curBufLength = newBufLength;
}
buf[count] = (byte) b;
count++;
}
public void flush() {
if (count <= 1) {
count = 0;
return;
}
final byte bytes = new byte[count];
System.arraycopy(buf, 0, bytes, 0, count);
String str = new String(bytes);
log.log(level, str);
count = 0;
}
public void close() {
flush();
hasBeenClosed = true;
}
}
And create a custom logger for system output stream, than register it.
Here is the complete code of the logger usage:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<Properties>
<Property name="log-pattern">%d{ISO8601} %-5p %mn</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
</Console>
</appenders>
<Loggers>
<logger name="testLogger" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
<logger name="systemOut" level="info" additivity="true"/>
</Loggers>
</configuration>
SystemLogging.java
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import java.io.PrintStream;
public class SystemLogging {
public void enableOutStreamLogging() {
System.setOut(createPrintStream("systemOut", Level.INFO));
}
private PrintStream createPrintStream(String name, Level level) {
return new PrintStream(new LoggingOutputStream(LogManager.getLogger(name), level), true);
}
}
LogApp.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogApp {
public static void main(String args) {
new SystemLogging().enableOutStreamLogging();
Logger log = LogManager.getLogger("testLogger");
log.info("Logger output test!");
System.out.println("System out test!");
}
}
Final output
2019-01-08T19:30:43,456 INFO Logger output test!
19:30:43.457 [main] INFO systemOut - System out test!
Now, customize system out with new logger configuration as you wish.
Plus; if you don't want to override System.out
and just want to save it: there is TeeOutputStream in commons-io library. You can just replace original System.out
with a combination of original System.out
and LoggingOutputStream
that will write simultaniously to both streams. This won't change the original output but allow you to save System.out
with a logging appender.
edited Jan 14 at 14:38
answered Jan 8 at 16:39
veysiertekinveysiertekin
579426
579426
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53993719%2fchange-appender-level-instead-of-the-logger-level%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Are you able to add a separate Logger for console and File appender? Like : <Logger name="task1Console" level="info"> <AppenderRef ref="Console"/> <AppenderRef ref="File"/> </Logger> <Logger name="task1File" level="info"> <AppenderRef ref="File"/> </Logger>
– don
Jan 7 at 7:13
Can you add code related with task/thread?
– Jonathan Johx
Jan 8 at 3:35