Log4j 2
  1. Log4j 2
  2. LOG4J2-486

RollingFile Appender - add custom info at the start of each logfile

    Details

    • Type: Question Question
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.0-beta9
    • Fix Version/s: 2.0-beta9
    • Component/s: Appenders
    • Labels:
      None
    • Environment:

      Java 1.7, Linux

      Description

      I post this question here because of a hint of Remko Popma.
      See also:

      I want to add some custom info at the top of each logfile, like the version string of my application, the application uptime and the system uptime. And even writing some »bye, bye / eof« to the bottom of the just closed logfile would also be fine.

      Because there is no appropriate hook or callback to get notified when the RollingFileAppander is creating / has created a new file, so that I can put my things at first into these new logfile, I tried to extend DefaultRolloverStrategy. But currently, I stuck at some points.

      Seems that I have to deal with @Plugin and @PluginFactory. My try with the attached log4j2.xml and MyRolloverStrategy.java compiles without errors and warnings. But when I start the application, I get this error message:
      2014-01-05 23:22:05,876 ERROR RollingFile contains an invalid element or attribute "MyRolloverStrategy"

      And then the next step would be: "how to write to the logfiles within my rollover method?"

      log4j2.xml :

      <?xml version="1.0" encoding="UTF-8"?>
      <Configuration>
        <Properties>
          <Property name="projectPrefix">Tts</Property>
          <Property name="rawPattern">%d %-5p [%t] %C{2} (%F:%L) - %m%n</Property>
          <Property name="coloredPattern">%d %highlight{%-5p}{FATAL=bright red, ERROR=red, WARN=yellow, INFO=cyan, DEBUG=green, TRACE=bright blue} %style{[%t] %C{2} (%F:%L) -}{bright,black} %m%n</Property>
          <Property name="coloredShortPattern">%d %highlight{%-5p}{FATAL=bright red, ERROR=red, WARN=yellow, INFO=cyan, DEBUG=green, TRACE=bright blue} %style{[%t] -}{bright,black} %m%n</Property>
          <Property name="fileName">Log/${projectPrefix}.log</Property>
          <Property name="filePattern">Log/${projectPrefix}-%i.log</Property>
        </Properties>
        <Appenders>
          <Console name="Stdout" target="SYSTEM_OUT">
            <PatternLayout pattern="${coloredPattern}"/>
          </Console>
          <RollingFile name="Logfile" fileName="${fileName}" filePattern="${filePattern}">
            <PatternLayout pattern="${rawPattern}"/>
            <Policies>
              <SizeBasedTriggeringPolicy size="16 MB"/>
            </Policies>
            <eeo.toolbox.MyRolloverStrategy fileIndex="min" max="16"/>
          </RollingFile>
        </Appenders>
        <Loggers>
          <Root level="info">
            <AppenderRef ref="Stdout"/>
            <AppenderRef ref="Logfile"/>
          </Root>
        </Loggers>
      </Configuration>
      
      1. MyRolloverStrategy.java
        2 kB
        Joe Merten
      2. log4j2.xml
        1 kB
        Joe Merten

        Issue Links

          Activity

          Hide
          Joe Merten added a comment -

          Insofar as I'm concerned, it can be closed.

          Show
          Joe Merten added a comment - Insofar as I'm concerned, it can be closed.
          Hide
          Ralph Goers added a comment -

          Closing - question was answered

          Show
          Ralph Goers added a comment - Closing - question was answered
          Hide
          Ralph Goers added a comment -

          This issue is already marked as resolved. It should be closed.

          I am planning on creating a new issue to do the work on the header/footer property. That issue and LOG4J2-491 will end up referencing each other but once the new issue is implemented 491 will get closed as won't fix - for the reasons we have already stated.

          Show
          Ralph Goers added a comment - This issue is already marked as resolved. It should be closed. I am planning on creating a new issue to do the work on the header/footer property. That issue and LOG4J2-491 will end up referencing each other but once the new issue is implemented 491 will get closed as won't fix - for the reasons we have already stated.
          Hide
          Remko Popma added a comment -

          Joe, I see what you mean. To clarify, can we assume that from your point of view, this ticket is superseded by LOG4J2-491 and this ticket can be closed?

          Ralph, Gary, we may have less of a use case now... Do you want to keep this ticket open to do work on the header/footer property?

          Show
          Remko Popma added a comment - Joe, I see what you mean. To clarify, can we assume that from your point of view, this ticket is superseded by LOG4J2-491 and this ticket can be closed? Ralph, Gary, we may have less of a use case now... Do you want to keep this ticket open to do work on the header/footer property?
          Hide
          Joe Merten added a comment -

          Remko said: > Could the dynamic content requirement be addressed with a system property (whose value is changed at runtime by the application) that is resolved (property name replaced by its value) every time rollover is done?
          Joe: > The content to add is dynamic and calculated at the time as the rollover occurs

          So when using a system property, I have to set the property immediately before it was evaluated.
          That's why I prefer a callback solution.

          Show
          Joe Merten added a comment - Remko said: > Could the dynamic content requirement be addressed with a system property (whose value is changed at runtime by the application) that is resolved (property name replaced by its value) every time rollover is done? Joe: > The content to add is dynamic and calculated at the time as the rollover occurs So when using a system property, I have to set the property immediately before it was evaluated. That's why I prefer a callback solution.
          Hide
          Remko Popma added a comment -

          Ralph, I saw Gary's suggestion but missed your response about interpolation. Sorry for the confusion.
          I guess the header/footer values could become quite lengthy, hence the idea to put the value in a separate file?
          My proposal (as an alternative to separate files) was to add header and footer attributes to the Layout config elements. (And the configured values for these attributes could also be interpolated.)

          I don't have a preference for how to do this (or for when to do this, for that matter. It seems like a "nice to have" kind of feature...)

          Show
          Remko Popma added a comment - Ralph, I saw Gary's suggestion but missed your response about interpolation. Sorry for the confusion. I guess the header/footer values could become quite lengthy, hence the idea to put the value in a separate file? My proposal (as an alternative to separate files) was to add header and footer attributes to the Layout config elements. (And the configured values for these attributes could also be interpolated.) I don't have a preference for how to do this (or for when to do this, for that matter. It seems like a "nice to have" kind of feature...)
          Hide
          Ralph Goers added a comment -

          Remko see Gary and my posts from yesterday. Gary proposed allowing the header and footer to be specified as files names/urls. I suggested that we should interpolate the contents of the files so that they could contain any lookup references.

          Show
          Ralph Goers added a comment - Remko see Gary and my posts from yesterday. Gary proposed allowing the header and footer to be specified as files names/urls. I suggested that we should interpolate the contents of the files so that they could contain any lookup references.
          Hide
          Remko Popma added a comment - - edited

          Just as an aside, you would never lose the ability to use XMLLayout: in your custom header/footer you can always include the necessary opening/closing XML...

          Could the dynamic content requirement be addressed with a system property (whose value is changed at runtime by the application) that is resolved (property name replaced by its value) every time rollover is done?

          Show
          Remko Popma added a comment - - edited Just as an aside, you would never lose the ability to use XMLLayout: in your custom header/footer you can always include the necessary opening/closing XML... Could the dynamic content requirement be addressed with a system property (whose value is changed at runtime by the application) that is resolved (property name replaced by its value) every time rollover is done?
          Hide
          Joe Merten added a comment - - edited

          Thanx for showing up these alternate solution, especially because it needs less code. But there are 2 reasons why I currently still prefer the »extend DefaultRolloverStrategy« solution:

          • The content to add is dynamic and calculated at the time as the rollover occurs
          • I won't lost the possibility to use XMLLayout

          Regarding access to the Layout:
          The OutputStreamManager gets the Layout in its ctor but only grabs the header and footer.
          Could that be changed, that the OutputStreamManager stores the Layout as a member (and provide it by a getLayout() method)?
          That would make me able to access the Layout from inside my RolloverStrategy.

          Show
          Joe Merten added a comment - - edited Thanx for showing up these alternate solution, especially because it needs less code. But there are 2 reasons why I currently still prefer the »extend DefaultRolloverStrategy« solution: The content to add is dynamic and calculated at the time as the rollover occurs I won't lost the possibility to use XMLLayout Regarding access to the Layout: The OutputStreamManager gets the Layout in its ctor but only grabs the header and footer. Could that be changed, that the OutputStreamManager stores the Layout as a member (and provide it by a getLayout() method)? That would make me able to access the Layout from inside my RolloverStrategy.
          Hide
          Remko Popma added a comment - - edited

          Team, an alternative would be to add header and footer elements to the log4j PatternLayout. (I just noticed this is similar to Gary's suggestion above...)

          One question I see is whether we would want to support properties in these elements. Property values could change at runtime so would need to be resolved every time the getHeader/Footer method is called.

          Show
          Remko Popma added a comment - - edited Team, an alternative would be to add header and footer elements to the log4j PatternLayout . (I just noticed this is similar to Gary's suggestion above...) One question I see is whether we would want to support properties in these elements. Property values could change at runtime so would need to be resolved every time the getHeader/Footer method is called.
          Hide
          Remko Popma added a comment - - edited

          Ralph, the PatternLayout class is final and its constructor is private so in practice this class cannot be subclassed. We may want to change that.

          Joe, just FYI, if the PatternLayout could be subclassed, this solution would be a lot shorter than the RolloverStrategy solution because (a) the factory method is much shorter and (b) you would not need any of the code for the custom RolloverDescription actions. To give you an idea of how much shorter this would be, the complete solution would look like this:

          @Plugin(name="HeaderFooterPatternLayout", category="Core", elementType="layout", printObject=true)
          public class MyPatternLayout extends PatternLayout {
              public MyPatternLayout(Configuration config, RegexReplacement replace, String pattern,
                      Charset charset, boolean alwaysWriteExceptions) {
                  super(config, replace, pattern, charset, alwaysWriteExceptions);
                  setHeader("*************************\n" //
                          + "*** Hello new logfile ***\n" //
                          + "*************************\n");
                  setFooter("****************************\n" //
                          + "*** Bye, bye old logfile ***\n" //
                          + "****************************\n");
              }
          
              // plus 12 lines for the @PluginFactory method
          }
          

          You are not using XMLLayout so no need to worry about the XML header.

          Another advantage of this approach is that you could make the header and footer attributes of the HeaderFooterPatternLayout configuration element, so you could configure these strings instead of coding them.

          Show
          Remko Popma added a comment - - edited Ralph, the PatternLayout class is final and its constructor is private so in practice this class cannot be subclassed. We may want to change that. Joe, just FYI, if the PatternLayout could be subclassed, this solution would be a lot shorter than the RolloverStrategy solution because (a) the factory method is much shorter and (b) you would not need any of the code for the custom RolloverDescription actions. To give you an idea of how much shorter this would be, the complete solution would look like this: @Plugin(name= "HeaderFooterPatternLayout" , category= "Core" , elementType= "layout" , printObject= true ) public class MyPatternLayout extends PatternLayout { public MyPatternLayout(Configuration config, RegexReplacement replace, String pattern, Charset charset, boolean alwaysWriteExceptions) { super (config, replace, pattern, charset, alwaysWriteExceptions); setHeader( "*************************\n" // + "*** Hello new logfile ***\n" // + "*************************\n" ); setFooter( "****************************\n" // + "*** Bye, bye old logfile ***\n" // + "****************************\n" ); } // plus 12 lines for the @PluginFactory method } You are not using XMLLayout so no need to worry about the XML header. Another advantage of this approach is that you could make the header and footer attributes of the HeaderFooterPatternLayout configuration element, so you could configure these strings instead of coding them.
          Hide
          Joe Merten added a comment -

          Ok, so for the moment I gave up trying to format my stuff with the appender's Layout and let it without timestamp.
          Thanks a very lot for your help

          Show
          Joe Merten added a comment - Ok, so for the moment I gave up trying to format my stuff with the appender's Layout and let it without timestamp. Thanks a very lot for your help
          Hide
          Ralph Goers added a comment -

          The layout currently isn't saved in the Manager so it isn't accessible from the RolloverStrategy.

          Show
          Ralph Goers added a comment - The layout currently isn't saved in the Manager so it isn't accessible from the RolloverStrategy.
          Hide
          Ralph Goers added a comment -

          Joe, I'm beginning to think there is some sort of communication problem here. I mentioned XMLLayout, etc to illustrate that we know using the header and footer works properly to do what you are trying to accomplish, not to tell you that you should use one of those layouts. If you wanted to add custom info after the begin XML tag that the existing header generates then you would want to override the XMLLayout, but you have only mentioned your desire to use the PatternLayout so that is what I am suggesting needs to be customized to meet your needs.

          Gary, Being able to supply a header and footer file is a good idea, although it wouldn't allow for dynamic content unless the data in the file is interpolated (which I think should be done).

          Show
          Ralph Goers added a comment - Joe, I'm beginning to think there is some sort of communication problem here. I mentioned XMLLayout, etc to illustrate that we know using the header and footer works properly to do what you are trying to accomplish, not to tell you that you should use one of those layouts. If you wanted to add custom info after the begin XML tag that the existing header generates then you would want to override the XMLLayout, but you have only mentioned your desire to use the PatternLayout so that is what I am suggesting needs to be customized to meet your needs. Gary, Being able to supply a header and footer file is a good idea, although it wouldn't allow for dynamic content unless the data in the file is interpolated (which I think should be done).
          Hide
          Joe Merten added a comment -

          → back to approach 1 (extending DefaultRolloverStrategy) ←

          Is there a way to access the RollingFile Appenders' Layout?

          Show
          Joe Merten added a comment - → back to approach 1 (extending DefaultRolloverStrategy) ← Is there a way to access the RollingFile Appenders' Layout?
          Hide
          Gary Gregory added a comment -

          I could imagine having a header file and footer file property.

          Also, this could be a header/footer property where you could escape the usual special chars like \n.

          Show
          Gary Gregory added a comment - I could imagine having a header file and footer file property. Also, this could be a header/footer property where you could escape the usual special chars like \n.
          Hide
          Joe Merten added a comment -

          As long as XMLLayout etc. are using getHeader/Footer() für their <?xml version... etc., it might not be a good idea to use the same mechanism for my custom info. It sounds, that loss the capability of using XMLLayout in combination with my custom info, isn't it?.
          I currently prefer to put my custom info into »logging entries« - maybe during generating LogEvents and formatting them using the Layout which was configured for the related Appender).

          Show
          Joe Merten added a comment - As long as XMLLayout etc. are using getHeader/Footer() für their <?xml version... etc., it might not be a good idea to use the same mechanism for my custom info. It sounds, that loss the capability of using XMLLayout in combination with my custom info, isn't it?. I currently prefer to put my custom info into »logging entries« - maybe during generating LogEvents and formatting them using the Layout which was configured for the related Appender).
          Hide
          Ralph Goers added a comment - - edited

          FWIW, the issue with PatternLayout not being dynamic is that OutputStreamManager is saving the header and footer string in its constructor. If it saved the layout reference instead it could then call getHeader() and getFooter() at the appropriate times which would allow you to dynamically generate them.

          I should also point out that XMLLayout, JSONLayout and HTMLLayout all use the header and footer to write the appropriate beginning and end of their document types, so we are pretty sure that this method works correctly for what you are trying to do.

          Show
          Ralph Goers added a comment - - edited FWIW, the issue with PatternLayout not being dynamic is that OutputStreamManager is saving the header and footer string in its constructor. If it saved the layout reference instead it could then call getHeader() and getFooter() at the appropriate times which would allow you to dynamically generate them. I should also point out that XMLLayout, JSONLayout and HTMLLayout all use the header and footer to write the appropriate beginning and end of their document types, so we are pretty sure that this method works correctly for what you are trying to do.
          Hide
          Joe Merten added a comment -

          Ok, for the initial problem »add custom info at the start of each logfile« we are currently discussing 2 approaches:

          1. extend DefaultRolloverStrategy (with wrapping RolloverDescriptor etc)
          2. extend PatternLayout (to setHeader/Footer, currently no dynamic contents (like uptime) possible)

          For the moment, I'm still discovering approach 1 (extend DefaultRolloverStrategy), were I do my custom stuff in the overridden Action.execute():

              static class MyAction implements Action {
                  ...
                  @Override public boolean execute() throws IOException {
                      boolean ret = delegate.execute();
          
                      try {
                          BufferedWriter writer = null;
                          try {
                              writer = new BufferedWriter(new FileWriter(new File(fileName), true));
                              writer.write("*************************\n");
                              writer.write("*** Hello new logfile ***\n");
                              writer.write("*************************\n");
                          } finally {
                              if (writer != null)
                                  writer.close();
                          }
                      } catch (Throwable e) {
                          logger.error("Writing to top of new logfile \"" + fileName + "\" with", e);
                      }
          
                      return ret;
                  }
          

          That results in logfiles like:

          *************************
          *** Hello new logfile ***
          *************************
          2014-01-07 15:07:56,715 INFO  [Tts XmlServer] tts.XmlServer (XmlServer.java:119) - XmlServer listens on port 42120
          2014-01-07 15:07:56,730 INFO  [Tts XmlServer] tts.XmlServer (XmlServer.java:119) - Connected
          

          But I want my logfiles like this:

          2014-01-07 15:07:56,700 INFO  [Thread] package.class - *************************
          2014-01-07 15:07:56,705 INFO  [Thread] package.class - *** Hello new logfile ***
          2014-01-07 15:07:56,710 INFO  [Thread] package.class - *************************
          2014-01-07 15:07:56,715 INFO  [Tts XmlServer] tts.XmlServer - XmlServer listens on port 42120
          2014-01-07 15:07:56,730 INFO  [Tts XmlServer] tts.XmlServer - Connected
          

          Therefor, I try to access the PatternLayout which is configured for related appender, so that I can use it inside my implementation of Action.execute() to format my messages.

          Show
          Joe Merten added a comment - Ok, for the initial problem »add custom info at the start of each logfile« we are currently discussing 2 approaches: extend DefaultRolloverStrategy (with wrapping RolloverDescriptor etc) extend PatternLayout (to setHeader/Footer, currently no dynamic contents (like uptime) possible) For the moment, I'm still discovering approach 1 (extend DefaultRolloverStrategy), were I do my custom stuff in the overridden Action.execute(): static class MyAction implements Action { ... @Override public boolean execute() throws IOException { boolean ret = delegate.execute(); try { BufferedWriter writer = null ; try { writer = new BufferedWriter( new FileWriter( new File(fileName), true )); writer.write( "*************************\n" ); writer.write( "*** Hello new logfile ***\n" ); writer.write( "*************************\n" ); } finally { if (writer != null ) writer.close(); } } catch (Throwable e) { logger.error( "Writing to top of new logfile \" " + fileName + " \ " with" , e); } return ret; } That results in logfiles like: ************************* *** Hello new logfile *** ************************* 2014-01-07 15:07:56,715 INFO [Tts XmlServer] tts.XmlServer (XmlServer.java:119) - XmlServer listens on port 42120 2014-01-07 15:07:56,730 INFO [Tts XmlServer] tts.XmlServer (XmlServer.java:119) - Connected But I want my logfiles like this: 2014-01-07 15:07:56,700 INFO [Thread] package.class - ************************* 2014-01-07 15:07:56,705 INFO [Thread] package.class - *** Hello new logfile *** 2014-01-07 15:07:56,710 INFO [Thread] package.class - ************************* 2014-01-07 15:07:56,715 INFO [Tts XmlServer] tts.XmlServer - XmlServer listens on port 42120 2014-01-07 15:07:56,730 INFO [Tts XmlServer] tts.XmlServer - Connected Therefor, I try to access the PatternLayout which is configured for related appender, so that I can use it inside my implementation of Action.execute() to format my messages.
          Hide
          Ralph Goers added a comment -

          You are not implementing your own PatternLayout. You are extending the existing one so that you can specify the header and/or footer information you want at the beginning and the end of the file. That is what the header and footer in the Layout interface are for.

          More than likely this issue will be closed as "not an issue", however I could see enhancing the PatternLayout so that the header and footer could be defined in the configuration or by referencing plugins to provide the information.

          Show
          Ralph Goers added a comment - You are not implementing your own PatternLayout. You are extending the existing one so that you can specify the header and/or footer information you want at the beginning and the end of the file. That is what the header and footer in the Layout interface are for. More than likely this issue will be closed as "not an issue", however I could see enhancing the PatternLayout so that the header and footer could be defined in the configuration or by referencing plugins to provide the information.
          Hide
          Joe Merten added a comment -

          > public class MyLayout ...
          I don't want to implement my own PatternLayout.
          I want to use the existing (already configured) PatternLayout, so that my added custom info (which I currently write using a simple writer.write("blabla")) has the same layout as all the rest of the logfile entries, including the current timestamp et cetera.

          Show
          Joe Merten added a comment - > public class MyLayout ... I don't want to implement my own PatternLayout. I want to use the existing (already configured) PatternLayout, so that my added custom info (which I currently write using a simple writer.write("blabla")) has the same layout as all the rest of the logfile entries, including the current timestamp et cetera.
          Hide
          Remko Popma added a comment -

          And LOG4J2-239 won't break your plugin: it would make it possible to omit the file name, but in your config you can of course specify the file name so you can be sure that it's there. (And even if it isn't you should still be able to use the rollover file name.)

          Show
          Remko Popma added a comment - And LOG4J2-239 won't break your plugin: it would make it possible to omit the file name, but in your config you can of course specify the file name so you can be sure that it's there. (And even if it isn't you should still be able to use the rollover file name.)
          Hide
          Remko Popma added a comment - - edited

          I think you can try the same thing:

          @Plugin name="HeaderLayout" ...
          public class MyLayout extends [standard log4j PatternLayout class]...
          

          and in config you replace PatternLayout elements with HeaderLayout elements.

          Show
          Remko Popma added a comment - - edited I think you can try the same thing: @Plugin name= "HeaderLayout" ... public class MyLayout extends [standard log4j PatternLayout class]... and in config you replace PatternLayout elements with HeaderLayout elements.
          Hide
          Joe Merten added a comment -

          Yep, packages="eeo.toolbox" was the trick to get my factory method called .
          Now I'm able to write to the bottom of the old as well as to the top of the new logfile using a simple FileWriter like this:

              static class MyAction implements Action {
                  final Action delegate;
                  final String fileName;
          
                  public MyAction(final Action delegate, final String fileName) {
                      this.delegate = delegate;
                      this.fileName = fileName;
                  }
          
                  @Override public void run() {
                      delegate.run();
                  }
          
                  @Override public boolean execute() throws IOException {
                      try {
                          BufferedWriter writer = null;
                          try {
                              writer = new BufferedWriter(new FileWriter(new File(fileName), true));
                              writer.write("****************************\n");
                              writer.write("*** Bye, bye old logfile ***\n");
                              writer.write("****************************\n");
                          } finally {
                              if (writer != null)
                                  writer.close();
                          }
                      } catch (Throwable e) {
                          logger.error("Writing to bottom of old logfile \"" + fileName + "\" with", e);
                      }
          
                      boolean ret = delegate.execute();
          
                      try {
                          BufferedWriter writer = null;
                          try {
                              writer = new BufferedWriter(new FileWriter(new File(fileName), true));
                              writer.write("*************************\n");
                              writer.write("*** Hello new logfile ***\n");
                              writer.write("*************************\n");
                          } finally {
                              if (writer != null)
                                  writer.close();
                          }
                      } catch (Throwable e) {
                          logger.error("Writing to top of new logfile \"" + fileName + "\" with", e);
                      }
          
                      return ret;
                  }
          

          ( … but I think my solution will not longer work as soon as #239 is implemented, so I'll be happy if there was a appropriate callback provided in future versions … )

          Could you give me a hint how I can use the configured PatternLayout to write to the logfiles?

          Show
          Joe Merten added a comment - Yep, packages="eeo.toolbox" was the trick to get my factory method called . Now I'm able to write to the bottom of the old as well as to the top of the new logfile using a simple FileWriter like this: static class MyAction implements Action { final Action delegate; final String fileName; public MyAction( final Action delegate, final String fileName) { this .delegate = delegate; this .fileName = fileName; } @Override public void run() { delegate.run(); } @Override public boolean execute() throws IOException { try { BufferedWriter writer = null ; try { writer = new BufferedWriter( new FileWriter( new File(fileName), true )); writer.write( "****************************\n" ); writer.write( "*** Bye, bye old logfile ***\n" ); writer.write( "****************************\n" ); } finally { if (writer != null ) writer.close(); } } catch (Throwable e) { logger.error( "Writing to bottom of old logfile \" " + fileName + " \ " with" , e); } boolean ret = delegate.execute(); try { BufferedWriter writer = null ; try { writer = new BufferedWriter( new FileWriter( new File(fileName), true )); writer.write( "*************************\n" ); writer.write( "*** Hello new logfile ***\n" ); writer.write( "*************************\n" ); } finally { if (writer != null ) writer.close(); } } catch (Throwable e) { logger.error( "Writing to top of new logfile \" " + fileName + " \ " with" , e); } return ret; } ( … but I think my solution will not longer work as soon as #239 is implemented, so I'll be happy if there was a appropriate callback provided in future versions … ) Could you give me a hint how I can use the configured PatternLayout to write to the logfiles?
          Hide
          Ralph Goers added a comment - - edited

          Actually, to add something to the file when it is created you do not need to create a custom appender. Instead, you need to extend PatternLayout and call the setHeader method in the constructor with whatever you want logged in the header. OutputStreamManager caches the header so it currently can't be changed dynamically with every file. If this is required then we should change this issue to be a bug against that.

          Show
          Ralph Goers added a comment - - edited Actually, to add something to the file when it is created you do not need to create a custom appender. Instead, you need to extend PatternLayout and call the setHeader method in the constructor with whatever you want logged in the header. OutputStreamManager caches the header so it currently can't be changed dynamically with every file. If this is required then we should change this issue to be a bug against that.
          Hide
          Remko Popma added a comment -

          About the config, please take a look at the manual page on plugins: http://logging.apache.org/log4j/2.x/manual/plugins.html

          You need to declare the packages that contain your plugin code in the top-level <Configuration> element. For example:

          <Configuration status="trace" packages="eeo.toolbox">
          ...
          </Configuration>
          

          Also, your custom elements are not named by their fully qualified java class name (eeo.toolbox.MyRolloverStrategy in this case), but instead by their plugin name. So, if your rollover strategy class looks like this:

          @Plugin(name="HeaderFooterRolloverStrategy"  category="Core", printObject=true)
          public class MyRolloverStrategy extends DefaultRolloverStrategy {
          ...
          

          then in your configuration you would say

              ...
              <RollingFile ... >
                ...
                <HeaderFooterRolloverStrategy fileIndex="min" max="16"/>
              </RollingFile>
          

          About writing to log files at the time of a rollover, first take a look at org.apache.logging.log4j.core.appender.rolling.RollingFileManager#rollover.
          This shows how the RolloverStrategy will be used. A RolloverStrategy returns a RolloverDescription, which has a synchronous and an asynchronous Action. If a synchronous action exists it will be executed in the current thread, if an asynchronous action exists it will be executed in a new thread.

          So here is where you would implement your custom behaviour. One way I can think of is to extend DefaultRolloverStrategy, and in the rollover method first call super, and wrap its result in a RolloverDescriptor of your own. The asynchronous action of this custom descriptor would simply return the asynchronous action of the original nested descriptor (zipping the old log file), but the synchronous action would be customized. For example, first execute the nested sync action (the file rename), and after that do your custom work to create the new file with your header info.

          Show
          Remko Popma added a comment - About the config, please take a look at the manual page on plugins: http://logging.apache.org/log4j/2.x/manual/plugins.html You need to declare the packages that contain your plugin code in the top-level <Configuration> element. For example: <Configuration status= "trace" packages= "eeo.toolbox" > ... </Configuration> Also, your custom elements are not named by their fully qualified java class name ( eeo.toolbox.MyRolloverStrategy in this case), but instead by their plugin name. So, if your rollover strategy class looks like this: @Plugin(name= "HeaderFooterRolloverStrategy" category= "Core" , printObject= true ) public class MyRolloverStrategy extends DefaultRolloverStrategy { ... then in your configuration you would say ... <RollingFile ... > ... <HeaderFooterRolloverStrategy fileIndex= "min" max= "16" /> </RollingFile> About writing to log files at the time of a rollover, first take a look at org.apache.logging.log4j.core.appender.rolling.RollingFileManager#rollover . This shows how the RolloverStrategy will be used. A RolloverStrategy returns a RolloverDescription , which has a synchronous and an asynchronous Action . If a synchronous action exists it will be executed in the current thread, if an asynchronous action exists it will be executed in a new thread. So here is where you would implement your custom behaviour. One way I can think of is to extend DefaultRolloverStrategy , and in the rollover method first call super, and wrap its result in a RolloverDescriptor of your own. The asynchronous action of this custom descriptor would simply return the asynchronous action of the original nested descriptor (zipping the old log file), but the synchronous action would be customized. For example, first execute the nested sync action (the file rename), and after that do your custom work to create the new file with your header info.

            People

            • Assignee:
              Unassigned
              Reporter:
              Joe Merten
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development