Change appender level instead of the logger level












5















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?










share|improve this question























  • 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
















5















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?










share|improve this question























  • 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














5












5








5








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?










share|improve this question














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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










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



















  • 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












1 Answer
1






active

oldest

votes


















2





+25









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.






share|improve this answer

























    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
    });


    }
    });














    draft saved

    draft discarded


















    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









    2





    +25









    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.






    share|improve this answer






























      2





      +25









      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.






      share|improve this answer




























        2





        +25







        2





        +25



        2




        +25





        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.






        share|improve this answer















        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.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jan 14 at 14:38

























        answered Jan 8 at 16:39









        veysiertekinveysiertekin

        579426




        579426
































            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            MongoDB - Not Authorized To Execute Command

            How to fix TextFormField cause rebuild widget in Flutter

            in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith