Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Feb 14, 2018 @ 12:44
    Bjarne Fyrstenborg
    0

    Write log to custom separate file

    When using the static LogHelper class in Umbraco it writes by default to UmbracoTraceLog file. https://our.umbraco.org/apidocs/csharp/api/Umbraco.Core.Logging.LogHelper.html

    Sometimes to might want to write to a separate file, e.g. when importing stuff. Is there a way to use LogHelper to write to a different file in some parts of the code or have a similar class which wrap to custom logger?

    At the moment I have the following in /Config/log4net.config

    <appender name="ProductImportAppender" type="log4net.Appender.RollingFileAppender">
        <file type="log4net.Util.PatternString" value="App_Data\Logs\ProductImportLog.%property{log4net:HostName}.txt" />
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <maximumFileSize value="5MB" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
        </layout>
        <encoding value="utf-8" />
      </appender>
    
      <logger name="ProductImportLogger" additivity="false">
        <level value="ERROR"/>
        <appender-ref ref="ProductImportAppender"/>
      </logger>
    

    Then in my import class I have.

    private static readonly ILog _logger = LogManager.GetLogger("ProductImportLogger");
    
    ...
    
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri(_baseUrl);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
        try
        {
            HttpResponseMessage response = await client.GetAsync("/GetProducts");
            if (response.IsSuccessStatusCode)
            {
                _logger.Info(string.Format("Successfully requesting product service. Returned Status Code: {0} {1}", (int)response.StatusCode, response.StatusCode));
    
                string jsondata = await response.Content.ReadAsStringAsync();
                return jsondata;
            }
            else
            {
                _logger.Error(string.Format("Error requesting product service. Returned Status Code: {0} {1}", (int)response.StatusCode, response.StatusCode));
            }
        }
        catch (HttpRequestException ex)
        {
            _logger.Error("Error requesting product service", ex);
        }
        //catch (TimeoutException ex)
        //{
        //    _logger.Error("Error request was timing out", ex);
        //}
        catch (TaskCanceledException ex)
        {
            _logger.Error("Error - request was cancelled", ex);
        }
    
        return "";
    }
    

    Can I somehow wrap the logger in a class similar to LogHelper so I don't need to call GetLogger() in the different files where I want to log details?

    /Bjarne

  • Anders Bjerner 487 posts 2989 karma points MVP 7x admin c-trib
    Feb 23, 2018 @ 19:44
    Anders Bjerner
    0

    You can handle this by only modifying the log4net configuration a bit, and then you can keep on using the static LogHelper class like you're used to.

    I've used this in the past, but I think something has changed a bit since then - so this may be a bit outdated. But from what I can see, it still works.

    When you set up a new Umbraco installation, your log4net.config file will have an appender element, that looks like this:

      <appender name="rollingFile" type="log4net.Appender.RollingFileAppender">
          <file type="log4net.Util.PatternString" value="App_Data\Logs\UmbracoTraceLog.%property{log4net:HostName}.txt" />
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <maximumFileSize value="5MB" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
        </layout>
        <encoding value="utf-8" />
      </appender>
    

    It's basically the configuration for the default logger. We can take a copy of that element to creator our own, but instead for calling it rollingFile, we could call it OurHestAppender like below:

      <appender name="OurHestAppender" type="Umbraco.Core.Logging.AsynchronousRollingFileAppender, Umbraco.Core">
        <file type="log4net.Util.PatternString" value="App_Data\Logs\OurHestLog.%property{log4net:HostName}.txt" />
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <maximumFileSize value="5MB" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
        </layout>
        <encoding value="utf-8" />
      </appender>
    

    Also notice that I've changed the type attribute to Umbraco.Core.Logging.AsynchronousRollingFileAppender, Umbraco.Core. I think this is necessary to get the namespace-based logic to work.

    You can then add a new logger element, that then uses the appender above:

      <logger name="Our.Hest">
        <level value="ALL" />
        <appender-ref ref="OurHestAppender" />
      </logger>
    

    With this in place, whenever you log something for a class within the Our.hest namespace, that information is logged to your custom log file ;)

    It appears that the same information is also appended to the main Umbraco log file. I don't think it used to be like that in the past, but I cant remember for sure.

    Anyways, with the changed list above, my entire log4net.config file then looks like:

    <?xml version="1.0"?>
    <log4net>
    
      <root>
        <priority value="Info"/>
        <appender-ref ref="AsynchronousLog4NetAppender" />
      </root>
    
      <appender name="rollingFile" type="log4net.Appender.RollingFileAppender">
          <file type="log4net.Util.PatternString" value="App_Data\Logs\UmbracoTraceLog.%property{log4net:HostName}.txt" />
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <maximumFileSize value="5MB" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
        </layout>
        <encoding value="utf-8" />
      </appender>
    
      <appender name="OurHestAppender" type="Umbraco.Core.Logging.AsynchronousRollingFileAppender, Umbraco.Core">
        <file type="log4net.Util.PatternString" value="App_Data\Logs\OurHestLog.%property{log4net:HostName}.txt" />
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <maximumFileSize value="5MB" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
        </layout>
        <encoding value="utf-8" />
      </appender>
    
      <appender name="AsynchronousLog4NetAppender" type="Log4Net.Async.ParallelForwardingAppender,Log4Net.Async">
        <appender-ref ref="rollingFile" />
      </appender>
    
      <!--Here you can change the way logging works for certain namespaces  -->
    
      <logger name="NHibernate">
        <level value="WARN" />
      </logger>
    
      <logger name="Our.Hest">
        <level value="ALL" />
        <appender-ref ref="OurHestAppender" />
      </logger>
    
    </log4net>
    
  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Feb 27, 2018 @ 10:38
    Bjarne Fyrstenborg
    0

    Hi Anders

    Thanks for the suggestions. Does that mean when using LogHelper only code inside the namespace Our.Hest is appended to the custom log file - would code inside the namespace Our.Hest.Unicorn also be appended to this log file or does it have the be the specific namespace?

    In my case I have MyProject.Library.Import where I want to use the custom log file. Futhermore I would also prefer it doesn't write to the Umbraco log file too as it doesn't in the code I posted.

  • Gonçalo Chaves 14 posts 146 karma points
    Oct 19, 2018 @ 07:49
    Gonçalo Chaves
    0

    Hi all,

    I just want to share with you my approach on this matter as I believe that could be a great way for many projects or custom umbraco implementations.

    The scenario is with multiple projects within your solution file. Let's say you have:

    • MyProj.Frontend.Web (with umbraco cms install)
    • MyProj.Frontend.Core (with some of our own custom code)
    • MyProj.Core.Data (with some of our own data access layer code)

    Now you would like to have each namespace/dll with is own log file with the corresponding log instructions on each file according to with the code context execution.

    It's start with the changes on the log4net.config file as mention before. You should have a declaration of 3 + 1 (of umbraco.core) logger attributes for each one above:

      <logger name="Umbraco.Core">
        <level value="All" />
        <appender-ref ref="AsynchronousLog4NetAppender" />
      </logger>
    
      <logger name="MyProj.Frontend.Core">
        <level value="All" />
        <appender-ref ref="MyProj.Frontend.Core.Appender" />
      </logger>
    ...
    

    Then the declaration of the appenders like:

      <appender name="AsynchronousLog4NetAppender" type="Log4Net.Async.ParallelForwardingAppender,Log4Net.Async">
        <appender-ref ref="rollingFile" />
      </appender>
    
      <appender name="MyProj.Frontend.Core.Appender" type="Log4Net.Async.ParallelForwardingAppender,Log4Net.Async">
        <appender-ref ref="MyProj.Frontend.Core.Appender.RollingFile" />
      </appender>
    

    and last, declarations for the appender log container itself (file, smtp, etc). For namespace Umbraco.Core:

     <appender name="rollingFile" type="log4net.Appender.RollingFileAppender">
          <file type="log4net.Util.PatternString" value="App_Data\Logs\MyProj.Umbraco.%property{log4net:HostName}.txt" />
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <maximumFileSize value="5MB" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
        </layout>
        <encoding value="utf-8" />
      </appender>
    

    and for your own:

     <appender name="MyProj.Frontend.Core.Appender.RollingFile" type="log4net.Appender.RollingFileAppender">
        <file type="log4net.Util.PatternString" value="App_Data\Logs\MyProj.Frontend.Core.%property{log4net:HostName}.txt" />
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <maximumFileSize value="5MB" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
        </layout>
        <encoding value="utf-8" />
      </appender>
    

    Keep in mind that you would need:

    1. declare the logger name for your namespace
    2. declare the appender of the logger name
    3. declare the container for the appender that you defined on the previous step.

    When you run your solution, you'll end up with:

    1. Umbraco.Core.hostname.log
    2. MyProj.Frontend.Core.hostname.log
    3. MyProj.Core.Data.hostname.log

    I hope that it helps because in my opinion is very useful that we could have different log files for each layer of our custom application that uses the umbraco cms. As of this matter, it allows you to focus or attention on the correct layer when you're facing issues.

  • Bo Jacobsen 590 posts 2366 karma points
    Nov 21, 2019 @ 09:34
    Bo Jacobsen
    0

    Hi Bjarne.

    Did you ever found a solution for this or did you go with Gonçalo solution?

Please Sign in or register to post replies

Write your reply to:

Draft