Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

Using log4net for logging ;-)

Discussion in 'Scripting' started by jashan, Jan 19, 2008.

  1. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,053
    Hi there,

    I think print(...) is really nice for many purposes, but in most cases, I prefer having different loglevels, the ability to write logs to different files, automatically receiving e-mails when things go very wrong (nice for standalone game servers) etc.

    One very nice logging API for .NET / Mono is log4net.

    However, if you include the log4net.dll and use it, not only does this DLL itself add to your Web player size (if you also build Web players), but also quite a few other DLLs are included. In my current project, the first level goes up from about 500kB to 3.3 MB when I include log4net (even though the log4net API itself only has about 250kB). This is not cool, because logging is quite useless in the Webplayer, so it's really just a big waste.

    As I've expected this to happen, I wrote a little wrapper. It's a simple C-Sharp file that implements the ILog interface. You can easily switch log4net on/off by replacing /**/ with /**/// which will comment out the calls into log4net. So, you only need to change one single file instead of going through all your code. That way, you can say "I want logging" (e.g. for standalone players), or "I don't want logging" (e.g. for Web players).

    Obviously, some preprocessor directives would simplify this even more. Would that be possible to implement in Unity? That would rock!!!

    I thought I'd share this with you... If the attachment works, you'll find a little example project included. In the project, there's also the Unity package you can easily include in your projects, if you wish.

    I'm not really into JavaScript... It should work from JavaScript, but I'll leave that to someone else. Would be nice... I've already included a JavaScript sample file, but it simply doesn't work. If someone can provide me a little JS sample, I'll be happy to include that in the sample project...

    Comments are very welcome! If this is useful to others, I might put it up to the UnifyWiki, too...

    Before running the project, be sure to change the path in log4net.xml!

    Jashan
     

    Attached Files:

  2. tbjod

    tbjod

    Joined:
    Feb 25, 2008
    Posts:
    19
    Hi


    I was just considering doing this myself but did a quick look in the forums first.
    Thanks, this saved me hours of work! :)
    I just prefere the pure functionality you get from log4j(netport..) instead of working with mono file streams when logging.
    + much nicer looking logs :)


    As you mentioned couldnt you just use C# Preprocessor Directives instead of having to comment out code you dont want to be there when building a release and dont want to log anything.
    http://www.jaggersoft.com/csharp_standard/9.5.htm
    Seems to work for me.


    Soinstead of

    Code (csharp):
    1.  
    2. using System;
    3. using UnityEngine;
    4.  
    5. public class Log4NetWrapper {
    6.    /**/private log4net.ILog log;
    7.    public Log4NetWrapper(Type type) {
    8.       /**/log = log4net.LogManager.GetLogger(type);
    9.     }
    10. ...
    11.  
    12.  
    Do this:

    Code (csharp):
    1.  
    2. #define LOG // Remove when not logging.
    3.  
    4. using System;
    5. using UnityEngine;
    6.  
    7. public class Log4NetWrapper {
    8.  
    9. #if LOG
    10.     private log4net.ILog log;
    11. #endif
    12.  
    13.    public Log4NetWrapper(Type type) {
    14. #if LOG
    15.      log = log4net.LogManager.GetLogger(type);
    16. #endif
    17.     }
    18. ...
    19.  
    20.  


    Cheers,
    Tobias
     
  3. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,053
    Hi Tobias,

    :oops: you're perfectly right! So I guess I have just outed myself as an IDE-junkie. As Unity doesn't seem to have a way to set global defines (as Visual Studio does), I assumed this to not work at all. Oh well, you never cease to learn ;-)

    In a way, I kind of like the possibility to do "single-line conditional compilation" as I did it with the "replace-comments-approach", but using proper conditional compilation sure is the better way, and for this particular script, that works perfectly as it's only a single file, so a #define on top of that file is all that's needed...

    I'll change that accordingly ;-) ... and ask UT if they would consider a way of passing global defines to the compiler, somehow ;-)

    Oh, btw - I have an updated version of this (I think that's still the old version in attached to this posting), which now supports both: log4net AND Debug.Log(...); for me, it turned out that in many cases, Debug.Log(...) is more useful, so it's great to be able to change easily...

    I'll just post the code real quick (no guarantees that it works - if it doesn't first thing to look at is the path to the configuration file; I might have changed that):

    Code (csharp):
    1. //#define LOG4NET
    2. //#define LOG_UNITY
    3.  
    4. // ... to be implemented ;-)
    5.  
    6. using System;
    7. using UnityEngine;
    8.  
    9. /// <summary>
    10. ///     This is a very simply class to abstract the use of log4net.
    11. ///     If log4net is included in the project, you simply use this
    12. ///     class as it is. If you remove the log4net.dll from your
    13. ///     project, all you have to do is comment out the relevant
    14. ///     statements in this class - you don't need to change any
    15. ///     other of your existing code that may be using log4net.
    16. ///    
    17. ///     You should definitely remove log4net when building Web players
    18. ///     as it increases the size significantly (around 1 to 2 MB!)
    19. ///
    20. ///     You can do a simple search and replace /**/ to /**///
    21. ///     to include or exclude logging...
    22. ///     Also, you can replace /*_*/ to /*_*/// to disable Debug.logs
    23. ///     of Unity...
    24. ///    
    25. ///     Version history:
    26. ///     1.0 - full log4net-support
    27. ///     1.1 - added support for Unity's Debug-logging
    28. ///     1.2 - [To Do] Use proper conditional compilation ;-)
    29. /// </summary>
    30. /// <version>1.1</version>
    31. /// <author>Jashan Chittesh - info (you know it) jashan-chittesh (dot) de</author>
    32. public class JCsLogger {
    33.     private const string startmsg
    34.         = "\nlog4net configuration file:\n{0}\n\n"
    35.         + "    =======================================\n"
    36.         + "    === Logging configured successfully ===\n"
    37.         + "    =======================================\n";
    38.  
    39.     /**/private log4net.ILog log;
    40.  
    41.     /// <summary>
    42.     ///     A logger to be used for logging statements in the code.
    43.     ///     It is recommended to follow a pattern for instantiating this:
    44.     ///     <code>
    45.     ///
    46.     ///     </code>
    47.     /// </summary>
    48.     /// <param name="type">the type that is using this logger</param>
    49.     public JCsLogger(Type type) {
    50.         /**/log = log4net.LogManager.GetLogger(type);
    51.     }
    52.  
    53.     /// <summary>
    54.     ///     This is automatically called before the first instance of
    55.     ///     JCsLogger is created, and initializes logging. You can change
    56.     ///     this according to your needs.
    57.     /// </summary>
    58.     static JCsLogger() {
    59.         if (Application.platform == RuntimePlatform.OSXWebPlayer
    60.             || Application.platform == RuntimePlatform.WindowsWebPlayer) {
    61.             // logging won't make a lot of sense in a Web player...
    62.             return;
    63.         }
    64.  
    65.         string configFile = Application.dataPath + "/Configuration/log4net.xml";
    66.         if (Application.platform == RuntimePlatform.WindowsPlayer) {
    67.             configFile = Application.dataPath + "\\Configuration\\log4net.xml";
    68.         }
    69.         Configure(configFile);
    70.     }
    71.  
    72.     public static void ConfigureForServer() {
    73.         Configure(Application.dataPath + "/Configuration/log4net_srv.xml");
    74.     }
    75.  
    76.     private static void Configure(string configFile) {
    77.         /**/System.IO.FileInfo fileInfo = new System.IO.FileInfo(configFile);
    78.         /**/log4net.Config.XmlConfigurator.ConfigureAndWatch(fileInfo);
    79.         /**/log4net.LogManager.GetLogger(typeof(JCsLogger)).InfoFormat(startmsg, configFile);
    80.     }
    81.  
    82.     /* Test if a level is enabled for logging */
    83.     public bool IsDebugEnabled {
    84.         get {
    85.             bool result = false;
    86.             /**/result = log.IsDebugEnabled;
    87.             return result;
    88.         }
    89.     }
    90.     public bool IsInfoEnabled {
    91.         get {
    92.             bool result = false;
    93.             /**/result = log.IsInfoEnabled;
    94.             return result;
    95.         }
    96.     }
    97.     public bool IsWarnEnabled {
    98.         get {
    99.             bool result = false;
    100.             /**/result = log.IsWarnEnabled;
    101.             return result;
    102.         }
    103.     }
    104.     public bool IsErrorEnabled {
    105.         get {
    106.             bool result = false;
    107.             /**/result = log.IsErrorEnabled;
    108.             return result;
    109.         }
    110.     }
    111.     public bool IsFatalEnabled {
    112.         get {
    113.             bool result = false;
    114.             /**/result = log.IsFatalEnabled;
    115.             return result;
    116.         }
    117.     }
    118.  
    119.     /* Log a message object */
    120.     public void Debug(object message) {
    121.         /**/log.Debug(message);
    122.         /*_*/if (IsDebugEnabled) {
    123.         /*_*/    UnityEngine.Debug.Log(message);
    124.         /*_*/}
    125.     }
    126.     public void Info(object message) {
    127.         /**/log.Info(message);
    128.         /*_*/if (IsInfoEnabled) {
    129.         /*_*/    UnityEngine.Debug.Log(message);
    130.         /*_*/}
    131.     }
    132.     public void Warn(object message) {
    133.         /**/log.Warn(message);
    134.         /*_*/if (IsWarnEnabled) {
    135.         /*_*/    UnityEngine.Debug.LogWarning(message);
    136.         /*_*/}
    137.     }
    138.     public void Error(object message) {
    139.         /**/log.Error(message);
    140.         /*_*/if (IsErrorEnabled) {
    141.         /*_*/    UnityEngine.Debug.LogError(message);
    142.         /*_*/}
    143.     }
    144.     public void Fatal(object message) {
    145.         /**/log.Fatal(message);
    146.         /*_*/if (IsFatalEnabled) {
    147.         /*_*/    UnityEngine.Debug.LogError(message);
    148.         /*_*/}
    149.     }
    150.  
    151.     /* Log a message object and exception */
    152.     public void Debug(object message, Exception t) {
    153.         /**/log.Debug(message, t);
    154.         /*_*/if (IsDebugEnabled) {
    155.         /*_*/    UnityEngine.Debug.Log(string.Format("{0}\n{1}: {2}\n{3}", message, t.GetType().ToString(), t.Message, t.StackTrace));
    156.         /*_*/}
    157.     }
    158.     public void Info(object message, Exception t) {
    159.         /**/log.Info(message, t);
    160.         /*_*/if (IsInfoEnabled) {
    161.         /*_*/    UnityEngine.Debug.Log(string.Format("{0}\n{1}: {2}\n{3}", message, t.GetType().ToString(), t.Message, t.StackTrace));
    162.         /*_*/}
    163.     }
    164.     public void Warn(object message, Exception t) {
    165.         /**/log.Warn(message, t);
    166.         /*_*/if (IsWarnEnabled) {
    167.         /*_*/    UnityEngine.Debug.LogWarning(string.Format("{0}\n{1}: {2}\n{3}", message, t.GetType().ToString(), t.Message, t.StackTrace));
    168.         /*_*/}
    169.     }
    170.     public void Error(object message, Exception t) {
    171.         /**/log.Error(message, t);
    172.         /*_*/if (IsErrorEnabled) {
    173.         /*_*/    UnityEngine.Debug.LogError(string.Format("{0}\n{1}: {2}\n{3}", message, t.GetType().ToString(), t.Message, t.StackTrace));
    174.         /*_*/}
    175.     }
    176.     public void Fatal(object message, Exception t) {
    177.         /**/log.Fatal(message, t);
    178.         /*_*/if (IsFatalEnabled) {
    179.         /*_*/    UnityEngine.Debug.LogError(string.Format("{0}\n{1}: {2}\n{3}", message, t.GetType().ToString(), t.Message, t.StackTrace));
    180.         /*_*/}
    181.     }
    182.  
    183.     /* Log a message string using the System.String.Format syntax */
    184.     public void DebugFormat(string format, params object[] args) {
    185.         /**/log.DebugFormat(format, args);
    186.         /*_*/if (IsDebugEnabled) {
    187.         /*_*/    UnityEngine.Debug.Log(string.Format(format, args));
    188.         /*_*/}
    189.     }
    190.     public void InfoFormat(string format, params object[] args) {
    191.         /**/log.InfoFormat(format, args);
    192.         /*_*/if (IsInfoEnabled) {
    193.         /*_*/    UnityEngine.Debug.Log(string.Format(format, args));
    194.         /*_*/}
    195.     }
    196.     public void WarnFormat(string format, params object[] args) {
    197.         /**/log.WarnFormat(format, args);
    198.         /*_*/if (IsWarnEnabled) {
    199.         /*_*/    UnityEngine.Debug.LogWarning(string.Format(format, args));
    200.         /*_*/}
    201.     }
    202.     public void ErrorFormat(string format, params object[] args) {
    203.         /**/log.ErrorFormat(format, args);
    204.         /*_*/if (IsErrorEnabled) {
    205.         /*_*/    UnityEngine.Debug.LogError(string.Format(format, args));
    206.         /*_*/}
    207.     }
    208.     public void FatalFormat(string format, params object[] args) {
    209.         /**/log.FatalFormat(format, args);
    210.         /*_*/if (IsFatalEnabled) {
    211.         /*_*/    UnityEngine.Debug.LogError(string.Format(format, args));
    212.         /*_*/}
    213.     }
    214.  
    215.     /* Log a message string using the System.String.Format syntax */
    216.     public void DebugFormat(IFormatProvider provider, string format, params object[] args) {
    217.         /**/log.DebugFormat(provider, format, args);
    218.         /*_*/if (IsDebugEnabled) {
    219.         /*_*/    UnityEngine.Debug.Log(string.Format(provider, format, args));
    220.         /*_*/}
    221.     }
    222.     public void InfoFormat(IFormatProvider provider, string format, params object[] args) {
    223.         /**/log.InfoFormat(provider, format, args);
    224.         /*_*/if (IsInfoEnabled) {
    225.         /*_*/    UnityEngine.Debug.Log(string.Format(provider, format, args));
    226.         /*_*/}
    227.     }
    228.     public void WarnFormat(IFormatProvider provider, string format, params object[] args) {
    229.         /**/log.WarnFormat(provider, format, args);
    230.         /*_*/if (IsWarnEnabled) {
    231.         /*_*/    UnityEngine.Debug.LogWarning(string.Format(provider, format, args));
    232.         /*_*/}
    233.     }
    234.     public void ErrorFormat(IFormatProvider provider, string format, params object[] args) {
    235.         /**/log.ErrorFormat(provider, format, args);
    236.         /*_*/if (IsErrorEnabled) {
    237.         /*_*/    UnityEngine.Debug.LogError(string.Format(provider, format, args));
    238.         /*_*/}
    239.     }
    240.     public void FatalFormat(IFormatProvider provider, string format, params object[] args) {
    241.         /**/log.FatalFormat(provider, format, args);
    242.         /*_*/if (IsFatalEnabled) {
    243.         /*_*/    UnityEngine.Debug.LogError(string.Format(provider, format, args));
    244.         /*_*/}
    245.     }
    246. }
    247.  

    Sunny regards,
    Jashan

    EDIT: I should not post my Mail-address, so I've made it less readable for spam-spiders...
     
  4. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,053
    Just thought I should put up my most recent version of this... it now uses defines (for a single-class that's working perfect - just comment the #define.s in and out as you need it). This now works with log4net, Unity's Debug.Log*, inside and outside of Unity. For using it outside of Unity (e.g. in a Unit testing environment, or, if you do "quick'n'dirty console app tests"), make sure to uncomment #define UNITY... and of course: Then LOG_UNITY won't work anymore ;-)

    It's mostly "self-documented"... please let me know if anything needs further documentation. I'll probably post this to the Wiki pretty soon so that it's easier to find...

    Code (csharp):
    1.  
    2. #define LOG4NET   // log4net logging active?
    3. #define LOG_UNITY // Debug.Log* active?
    4. #define UNITY // running inside the unity runtime environment?
    5.  
    6. using System;
    7. #if UNITY
    8. using UnityEngine; // you can disable this - recommended when using outside of Unity!
    9. #endif
    10.  
    11. /// <summary>
    12. ///     This is a very simply class to abstract the use of log4net.
    13. ///     If log4net is included in the project, you simply use this
    14. ///     class as it is. If you remove the log4net.dll from your
    15. ///     project, all you have to do is uncomment
    16. ///     #define LOG4NET (say //#define LOG4NET)
    17. ///     at the top of this file.
    18. ///    
    19. ///     You should definitely remove log4net when building Web players
    20. ///     as it increases the size significantly (around 1 to 2 MB!)
    21. ///    
    22. ///     You can also use this to use Unity's Debug.Log(...). If you have
    23. ///     log4net enabled, you can even use log4net's debug levels for this.
    24. ///     You could also use this only to use Debug.Log(...), though,
    25. ///     without using log4net at all. The choice is yours!!!
    26. ///
    27. ///     Version history:
    28. ///     1.0 - full log4net-support
    29. ///     1.1 - added support for Unity's Debug-logging
    30. ///     1.2 - Use proper conditional compilation ;-)
    31. /// </summary>
    32. /// <version>1.2</version>
    33. /// <author>Jashan Chittesh - jc (you know it) ramtiga (dot) com</author>
    34. public class JCsLogger {
    35.     private const string startmsg
    36.         = "\nlog4net configuration file:\n{0}\n\n"
    37.         + "    =======================================\n"
    38.         + "    === Logging configured successfully ===\n"
    39.         + "    =======================================\n";
    40. #if LOG4NET
    41.     private log4net.ILog log;
    42. #endif
    43.  
    44.     /// <summary>
    45.     ///     A logger to be used for logging statements in the code.
    46.     ///     It is recommended to follow a pattern for instantiating this:
    47.     ///     <code>
    48.     ///         private static readonly JCsLogger log = new JCsLogger(typeof(YourClassName));
    49.     ///         ...
    50.     ///         log.*(yourLoggingStuff); // Debug/Info/Warn/Error/Fatal[Format]
    51.     ///     </code>
    52.     /// </summary>
    53.     /// <param name="type">the type that is using this logger</param>
    54.     public JCsLogger(Type type) {
    55. #if LOG4NET
    56.         log = log4net.LogManager.GetLogger(type);
    57. #endif
    58.     }
    59.  
    60.     /// <summary>
    61.     ///     This is automatically called before the first instance of
    62.     ///     JCsLogger is created, and initializes logging. You can change
    63.     ///     this according to your needs.
    64.     /// </summary>
    65.     static JCsLogger() {
    66. #if UNITY
    67.         if (Application.platform == RuntimePlatform.OSXWebPlayer
    68.             || Application.platform == RuntimePlatform.WindowsWebPlayer) {
    69.             // logging won't make a lot of sense in a Web player...
    70.             return;
    71.         }
    72.  
    73.         string configFile = Application.dataPath + "/Configuration/log4net.xml";
    74.         if (Application.platform == RuntimePlatform.WindowsPlayer) {
    75.             configFile = Application.dataPath + "\\Configuration\\log4net.xml";
    76.         }
    77.         Configure(configFile);
    78. #endif // UNITY
    79.     }
    80.  
    81.     public static void ConfigureForServer() {
    82. #if UNITY
    83.         Configure(Application.dataPath + "/Configuration/log4net_srv.xml");
    84. #endif
    85.     }
    86.  
    87.     private static void Configure(string configFile) {
    88. #if LOG4NET
    89.         System.IO.FileInfo fileInfo = new System.IO.FileInfo(configFile);
    90.         log4net.Config.XmlConfigurator.ConfigureAndWatch(fileInfo);
    91.         log4net.LogManager.GetLogger(typeof(JCsLogger)).InfoFormat(startmsg, configFile);
    92. #endif
    93.     }
    94.  
    95.     #region Test if a level is enabled for logging - Only works when log4net is active!
    96.     public bool IsDebugEnabled {
    97.         get {
    98.             bool result = false;
    99. #if LOG4NET
    100.             result = log.IsDebugEnabled;
    101. #endif
    102.             return result;
    103.         }
    104.     }
    105.  
    106.  
    107.     public bool IsInfoEnabled {
    108.         get {
    109.             bool result = false;
    110. #if LOG4NET
    111.             result = log.IsInfoEnabled;
    112. #endif
    113.             return result;
    114.         }
    115.     }
    116.  
    117.  
    118.     public bool IsWarnEnabled {
    119.         get {
    120.             bool result = false;
    121. #if LOG4NET
    122.             result = log.IsWarnEnabled;
    123. #endif
    124.             return result;
    125.         }
    126.     }
    127.  
    128.  
    129.     public bool IsErrorEnabled {
    130.         get {
    131.             bool result = false;
    132. #if LOG4NET
    133.             result = log.IsErrorEnabled;
    134. #endif
    135.             return result;
    136.         }
    137.     }
    138.  
    139.  
    140.     public bool IsFatalEnabled {
    141.         get {
    142.             bool result = false;
    143. #if LOG4NET
    144.             result = log.IsFatalEnabled;
    145. #endif
    146.             return result;
    147.         }
    148.     }
    149.     #endregion Test if a level is enabled for logging
    150.  
    151.  
    152.  
    153.     /* Log a message object */
    154.     public void Debug(object message) {
    155. #if LOG4NET
    156.         log.Debug(message);
    157. #endif
    158. #if LOG_UNITY
    159.         if (IsDebugEnabled) {
    160.             UnityEngine.Debug.Log(message);
    161.         }
    162. #endif
    163.     }
    164.  
    165.  
    166.     public void Info(object message) {
    167. #if LOG4NET
    168.         log.Info(message);
    169. #endif
    170. #if LOG_UNITY
    171.         if (IsInfoEnabled) {
    172.             UnityEngine.Debug.Log(message);
    173.         }
    174. #endif
    175.     }
    176.  
    177.  
    178.     public void Warn(object message) {
    179. #if LOG4NET
    180.         log.Warn(message);
    181. #endif
    182. #if LOG_UNITY
    183.         if (IsWarnEnabled) {
    184.             UnityEngine.Debug.LogWarning(message);
    185.         }
    186. #endif
    187.     }
    188.  
    189.  
    190.     public void Error(object message) {
    191. #if LOG4NET
    192.         log.Error(message);
    193. #endif
    194. #if LOG_UNITY
    195.         if (IsErrorEnabled) {
    196.             UnityEngine.Debug.LogError(message);
    197.         }
    198. #endif
    199.     }
    200.  
    201.  
    202.     public void Fatal(object message) {
    203. #if LOG4NET
    204.         log.Fatal(message);
    205. #endif
    206. #if LOG_UNITY
    207.         if (IsFatalEnabled) {
    208.             UnityEngine.Debug.LogError(message);
    209.         }
    210. #endif
    211.     }
    212.  
    213.  
    214.  
    215.  
    216.     /* Log a message object and exception */
    217.     public void Debug(object message, Exception t) {
    218. #if LOG4NET
    219.         log.Debug(message, t);
    220. #endif
    221. #if LOG_UNITY
    222.         if (IsDebugEnabled) {
    223.             UnityEngine.Debug.Log(string.Format("{0}\n{1}: {2}\n{3}", message, t.GetType().ToString(), t.Message, t.StackTrace));
    224.         }
    225. #endif
    226.     }
    227.  
    228.  
    229.     public void Info(object message, Exception t) {
    230. #if LOG4NET
    231.         log.Info(message, t);
    232. #endif
    233. #if LOG_UNITY
    234.         if (IsInfoEnabled) {
    235.             UnityEngine.Debug.Log(string.Format("{0}\n{1}: {2}\n{3}", message, t.GetType().ToString(), t.Message, t.StackTrace));
    236.         }
    237. #endif
    238.     }
    239.  
    240.  
    241.     public void Warn(object message, Exception t) {
    242. #if LOG4NET
    243.         log.Warn(message, t);
    244. #endif
    245. #if LOG_UNITY
    246.         if (IsWarnEnabled) {
    247.             UnityEngine.Debug.LogWarning(string.Format("{0}\n{1}: {2}\n{3}", message, t.GetType().ToString(), t.Message, t.StackTrace));
    248.         }
    249. #endif
    250.     }
    251.  
    252.  
    253.     public void Error(object message, Exception t) {
    254. #if LOG4NET
    255.         log.Error(message, t);
    256. #endif
    257. #if LOG_UNITY
    258.         if (IsErrorEnabled) {
    259.             UnityEngine.Debug.LogError(string.Format("{0}\n{1}: {2}\n{3}", message, t.GetType().ToString(), t.Message, t.StackTrace));
    260.         }
    261. #endif
    262.     }
    263.  
    264.  
    265.     public void Fatal(object message, Exception t) {
    266. #if LOG4NET
    267.         log.Fatal(message, t);
    268. #endif
    269. #if LOG_UNITY
    270.         if (IsFatalEnabled) {
    271.             UnityEngine.Debug.LogError(string.Format("{0}\n{1}: {2}\n{3}", message, t.GetType().ToString(), t.Message, t.StackTrace));
    272.         }
    273. #endif
    274.     }
    275.  
    276.  
    277.  
    278.  
    279.     /* Log a message string using the System.String.Format syntax */
    280.     public void DebugFormat(string format, params object[] args) {
    281. #if LOG4NET
    282.         log.DebugFormat(format, args);
    283. #endif
    284. #if LOG_UNITY
    285.         if (IsDebugEnabled) {
    286.             UnityEngine.Debug.Log(string.Format(format, args));
    287.         }
    288. #endif
    289.     }
    290.  
    291.  
    292.     public void InfoFormat(string format, params object[] args) {
    293. #if LOG4NET
    294.         log.InfoFormat(format, args);
    295. #endif
    296. #if LOG_UNITY
    297.         if (IsInfoEnabled) {
    298.             UnityEngine.Debug.Log(string.Format(format, args));
    299.         }
    300. #endif
    301.     }
    302.  
    303.  
    304.     public void WarnFormat(string format, params object[] args) {
    305. #if LOG4NET
    306.         log.WarnFormat(format, args);
    307. #endif
    308. #if LOG_UNITY
    309.         if (IsWarnEnabled) {
    310.             UnityEngine.Debug.LogWarning(string.Format(format, args));
    311.         }
    312. #endif
    313.     }
    314.  
    315.  
    316.     public void ErrorFormat(string format, params object[] args) {
    317. #if LOG4NET
    318.         log.ErrorFormat(format, args);
    319. #endif
    320. #if LOG_UNITY
    321.         if (IsErrorEnabled) {
    322.             UnityEngine.Debug.LogError(string.Format(format, args));
    323.         }
    324. #endif
    325.     }
    326.  
    327.  
    328.     public void FatalFormat(string format, params object[] args) {
    329. #if LOG4NET
    330.         log.FatalFormat(format, args);
    331. #endif
    332. #if LOG_UNITY
    333.         if (IsFatalEnabled) {
    334.             UnityEngine.Debug.LogError(string.Format(format, args));
    335.         }
    336. #endif
    337.     }
    338.  
    339.  
    340.  
    341.     /* Log a message string using the System.String.Format syntax */
    342.     public void DebugFormat(IFormatProvider provider, string format, params object[] args) {
    343. #if LOG4NET
    344.         log.DebugFormat(provider, format, args);
    345. #endif
    346. #if LOG_UNITY
    347.         if (IsDebugEnabled) {
    348.             UnityEngine.Debug.Log(string.Format(provider, format, args));
    349.         }
    350. #endif
    351.     }
    352.  
    353.  
    354.     public void InfoFormat(IFormatProvider provider, string format, params object[] args) {
    355. #if LOG4NET
    356.         log.InfoFormat(provider, format, args);
    357. #endif
    358. #if LOG_UNITY
    359.         if (IsInfoEnabled) {
    360.             UnityEngine.Debug.Log(string.Format(provider, format, args));
    361.         }
    362. #endif
    363.     }
    364.  
    365.  
    366.     public void WarnFormat(IFormatProvider provider, string format, params object[] args) {
    367. #if LOG4NET
    368.         log.WarnFormat(provider, format, args);
    369. #endif
    370. #if LOG_UNITY
    371.         if (IsWarnEnabled) {
    372.             UnityEngine.Debug.LogWarning(string.Format(provider, format, args));
    373.         }
    374. #endif
    375.     }
    376.  
    377.  
    378.     public void ErrorFormat(IFormatProvider provider, string format, params object[] args) {
    379. #if LOG4NET
    380.         log.ErrorFormat(provider, format, args);
    381. #endif
    382. #if LOG_UNITY
    383.         if (IsErrorEnabled) {
    384.             UnityEngine.Debug.LogError(string.Format(provider, format, args));
    385.         }
    386. #endif
    387.     }
    388.  
    389.  
    390.     public void FatalFormat(IFormatProvider provider, string format, params object[] args) {
    391. #if LOG4NET
    392.         log.FatalFormat(provider, format, args);
    393. #endif
    394. #if LOG_UNITY
    395.         if (IsFatalEnabled) {
    396.             UnityEngine.Debug.LogError(string.Format(provider, format, args));
    397.         }
    398. #endif
    399.     }
    400. }
    401.  

    EDIT: I should not post my Mail-address, so I've made it less readable for spam-spiders...
     

    Attached Files:

  5. sennahoj

    sennahoj

    Joined:
    Jul 26, 2010
    Posts:
    7
    Nice logger jashan. I have a slightly different question to you:

    Did you ever try logging to a file by using the log4net layout type "log4net.Layout.XmlLayout"?

    I successfully included log4net into my project and I tried your Unity project, too. I always get the same problem: Unity Editor crashes at least the 2nd time I run my project and thus write to the File specified in the File Appender, if I use the XMLLayout. As soon as I switch back to PatternLayout, everything works fine again.

    I tried to change a lot of settings, like the "conversionPattern" or the "lockingModel", but I never get the XmlLayout running. Does somebody face the same problems with the XmlLayout?
     
  6. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,053
    I haven't tried the XmlLayout, sorry.
     
  7. the_gnoblin

    the_gnoblin

    Joined:
    Jan 10, 2009
    Posts:
    722
    Thanks for sharing,
    lots of time passed - still very useful! )
     
  8. justinlloyd

    justinlloyd

    Joined:
    Aug 5, 2010
    Posts:
    1,679
    These are two great logging libraries that you may want to dive in to, they are lighter weight than log4net, completely .NET and are incredibly easy to set up and port to Unity. You can add an extra logging sink in the form of Unity's Debug.Log for your debug builds so you can still see the logging output whilst running in the IDE.

    http://www.theobjectguy.com/dotnetlog/ (this one costs $5 but is worth the price, maybe we should convince him to sell it on the asset store?)
    http://nlog-project.org/
     
  9. kolmich

    kolmich

    Joined:
    Apr 27, 2009
    Posts:
    147
  10. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    223
    Hi jashan,

    Thanks for sharing your work, it provided exactly what I was looking for.

    I made a small improvement and also like to share it. Instead of logging to the Unity console directly, I wrote a ConsoleAppender, so one can enable/disable logging to the Unity console via the log4net.xml configuration.

    Code (csharp):
    1.  
    2. public class ConsoleAppender : AppenderSkeleton
    3. {
    4.     protected override void Append(LoggingEvent loggingEvent)
    5.     {
    6.         string message = this.RenderLoggingEvent(loggingEvent);
    7.         if (loggingEvent.Level == Level.Error)
    8.         {
    9.             Debug.LogError(message);
    10.         }
    11.         else if (loggingEvent.Level == Level.Warn)
    12.         {
    13.             Debug.LogWarning(message);
    14.         }
    15.         else
    16.         {
    17.             Debug.Log(message);
    18.         }
    19.     }
    20. }
    21.  
    To log to the Unity console you now just have to tell log4net to use your custom appender:

    Code (csharp):
    1.  
    2.     <!-- Appends the logs to the Unity console -->
    3.     <appender name="ConsoleAppender" type="Namespace.To.Appender.ConsoleAppender">
    4.         <layout type="log4net.Layout.PatternLayout">
    5.             <conversionPattern value="[%6rms] %-5level %-10logger - %message" />
    6.         </layout>
    7.     </appender>
    8.  
    Code (csharp):
    1.  
    2.     <root>
    3.         <level value="DEBUG" />
    4.         <appender-ref ref="FileAppender" />
    5.         <appender-ref ref="RollingFileAppender" />
    6.         <appender-ref ref="ConsoleAppender" />
    7.     </root>
    8.  
    Advantages:
    • Disable/Enable console logging via configuration instead of code
    • Configuring logging format via configuration

    Enjoy :)
     
  11. yoyo

    yoyo

    Joined:
    Apr 16, 2010
    Posts:
    112
    @coeing, nice addition -- just one question, how do I get an application config file to work with Unity? Can it be done for Windows, Mac, web player, and mobile?

    Also wanted to point out a couple things related to logging. Firstly, as of Unity 4 you can set project-wide preprocessor defines via Edit > Project Settings > Player, which is great for globally enabling/disabling things like log functionality. Secondly, System.Diagnostics.Trace and friends is -almost- a viable logging solution that won't add anything to your build size, as it is already in System.dll. I say "almost" because there are at least a couple of bugs in Unity's stale Mono implementation that make System.Diagnostics.Trace a little awkward to work with.
     
  12. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    146
    It wont compile due to System.Web being referenced by the DLL even when the target platform is a PC
     
  13. zotai

    zotai

    Joined:
    Jan 23, 2015
    Posts:
    5
    I've been using log4net for some time in my projects now and it's running into issues where methods are not found for log4net types when compiling with either il2cpp (both engine code stripping and not) or mono2x with code stripping.

    Has anyone else ran into this issue?
     
  14. am1goo_41

    am1goo_41

    Joined:
    Sep 8, 2016
    Posts:
    1
    Please, change API Compatibility Level in Player Settings from .NET 2.0 Subset to .NET 2.0