Dynamic CRM插件中记录日志的方式有多种 通常情况下分为ITracingService记录、单独日志表插入记录、文本记录三种,本文引用Nlog实现插件中日志记录到文本中,并附上Nlog帮助类和服务器Nlog.cofig配置
Dynamic CRM插件中记录日志的方式有多种 通常情况下分为ITracingService记录、单独日志表插入记录、文本记录三种。
之前整理过ITracingService记录的方式,但这种记录有限制,只有存在异常时才会在插件跟踪日志中查到,异常报错时排查问题到可以,但插件详细的日志记录查看就不很方便,并且插件跟踪日志中记录到最上层的插件,直接通过插件名查询不方便。
单独日志表的方式,也很简单,自定义一个日志表,在插件中调用封装好的日志插入方法即可,但这个存在一个致命的问题,像是普通的信息记录没问题,若存在异常,插入操作会回滚,所以无法通过这种记录排查异常。
第三种文本记录,需要引用第三方组件,比如Nlog或者Lognet4,我使用的Nlog
Nlog日志记录单例类早就有封装,可以在插件程序集中直接引用过来,最核心的地方就是Nlog的config文件,在插件程序集中不需要单独放置一份NLog.config,只需要在CRM的应用服务的Dynamics 365\CRMWeb\bin文件夹中放置好即可,并且保证CRMWeb里bin中的NLog.dll与插件程序集中引用的版本一致
提示:
1.通常服务器上CRMWeb路径为:C:\Program Files\Dynamics 365\CRMWeb\bin
2.NLog.config中具体指明一下文件存放的路径

附上NLog帮助类和服务器上NLog.config配置:
1 /// <summary> 2 /// Nlog日志帮助类 3 /// </summary> 4 public class LoggerHelper 5 { 6 #region 单例模式 7 private LoggerHelper() 8 { 9 } 10 private static readonly object LockObj = new object(); 11 private static LoggerHelper _instance; 12 13 /// <summary> 14 /// 获得对象实例 15 /// </summary> 16 public static LoggerHelper Instance 17 { 18 get 19 { 20 lock (LockObj) 21 { 22 if (_instance == null) 23 { 24 _instance = new LoggerHelper(); 25 } 26 return _instance; 27 } 28 } 29 } 30 31 #endregion 单例模式 32 33 #region 属性 34 35 private Logger _log; 36 /// <summary> 37 /// 日志实例 38 /// </summary> 39 public Logger Log 40 { 41 get 42 { 43 if (_log == null) _log = LogManager.GetCurrentClassLogger(); 44 return _log; 45 } 46 private set { _log = value; } 47 } 48 #endregion 属性 49 50 #region 方法 51 52 #region 普通方式 53 public void Debug(string msg) 54 { 55 Log.Debug(msg); 56 } 57 public void Debug(string msg, params object[] args) 58 { 59 Log.Debug(msg, args); 60 } 61 public void Debug(string msg, Exception ex) 62 { 63 Log.Debug(ex, msg); 64 } 65 public void Warn(string msg) 66 { 67 Log.Warn(msg); 68 } 69 public void Warn(string msg, params object[] args) 70 { 71 Log.Warn(msg, args); 72 } 73 public void Warn(string msg, Exception ex) 74 { 75 Log.Warn(ex, msg); 76 } 77 public void Trace(string msg) 78 { 79 Log.Trace(msg); 80 } 81 public void Trace(string msg, params object[] args) 82 { 83 Log.Trace(msg, args); 84 } 85 public void Trace(string msg, Exception ex) 86 { 87 Log.Trace(ex, msg); 88 } 89 public void Fatal(string msg, params object[] args) 90 { 91 Log.Fatal(msg, args); 92 } 93 94 public void Fatal(string msg, Exception ex) 95 { 96 Log.Fatal(ex, msg); 97 } 98 #endregion 普通方式 99 100 #region 运行时日志101 /// <summary>102 /// 运行时日志 103 /// </summary>104 /// <param name="msg">记录的信息</param>105 public void Info(string msg)106 {107 LogEventInfo logInfo = SetCustomInfo(LogLevel.Info, "Runlog", msg);108 Log.Log(LogLevel.Info, logInfo);109 }110 #endregion 运行时日志111 112 #region 错误日志113 /// <summary>114 /// 错误记录115 /// </summary>116 /// <param name="msg">方法名</param>117 /// <param name="ex">异常</param>118 public void Error(string msg)119 {120 LogEventInfo logInfo = SetCustomInfo(LogLevel.Error, "ExceptionLogger", msg);121 logInfo.Properties["ErrorHead"] = "程序发生错误:";122 Log.Log(LogLevel.Error, logInfo);123 }124 /// <summary>125 /// 错误记录126 /// </summary>127 /// <param name="msg">方法名</param>128 /// <param name="ex">异常</param>129 public void Error(string msg, Exception ex)130 {131 LogEventInfo logInfo = SetCustomInfo(LogLevel.Error, "ExceptionLogger", msg);132 logInfo.Properties["ErrorHead"] = "程序发生错误:";133 logInfo.Exception = ex;134 Log.Log(LogLevel.Error, logInfo);135 }136 #endregion 错误日志137 138 #region 私有方法139 /// <summary>140 /// 设置自定义日志事件141 /// </summary>142 /// <param name="level"></param>143 /// <param name="loggerName"></param>144 /// <param name="message"></param>145 /// <param name="customPropertie"></param>146 /// <param name="customPropertieValue"></param>147 /// <returns></returns>148 private LogEventInfo SetCustomInfo(LogLevel level, string loggerName, string message, string customPropertie = "", string customPropertieValue = "")149 {150 LogEventInfo ei = new LogEventInfo(level, loggerName, message); //也可以用LogEventInfo.Create(level, loggerName, message);151 if (!string.IsNullOrEmpty(customPropertie) && !string.IsNullOrEmpty(customPropertieValue))152 ei.Properties[customPropertie] = customPropertieValue;153 return ei;154 155 }156 #endregion 私有方法157 158 #endregion 方法NLog.config配置:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd" 5 autoReload="true"> 6 7 <!-- Use below one for debugging--> 8 <!--nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" 9 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"10 xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"11 autoReload="true"12 throwExceptions="true" 13 internalLogLevel="Trace" 14 internalLogFile="c:\temp\nlog-internal.log"-->15 16 <extensions>17 <add assembly="Microsoft.Xrm.Log"/>18 </extensions>19 20 <variable name="floderInfo" value="Info"/>21 <variable name="floderError" value="Error"/>22 23 <targets>24 <target name="XrmTraceETWTarget" xsi:type="XrmTraceETWTarget" />25 26 <target name="DataProviderExecutionETWTarget" xsi:type="DataProviderExecutionETWTarget" />27 <!-- ${basedir} -->28 <target name="XrmTraceFileTarget" xsi:type="File"29 layout="${longdate}|${logger}|${level:uppercase=true}|${message}|${all-event-properties}|${exception:format=tostring}"30 fileName="D:/CrmLog/logs/logfile.txt"31 archiveFileName="D:/CrmLog/archives/log.{#####}.txt"32 archiveAboveSize="1024000"33 archiveNumbering="Sequence"34 concurrentWrites="true"35 keepFileOpen="false"36 encoding="utf-8" />37 <!-- ${basedir} -->38 <target name="debug_info_file" xsi:type="File"39 layout="${longdate}|${logger}|${level:uppercase=true}|${message}|${all-event-properties}|${exception:format=tostring}"40 fileName="D:/CrmLog/logs/${floderInfo}/${shortdate}.txt"41 archiveFileName="D:/CrmLog/archives/${shortdate}.{#####}.txt"42 archiveAboveSize="1024000"43 archiveNumbering="Sequence"44 concurrentWrites="true"45 keepFileOpen="false"46 encoding="utf-8" />47 <!--错误记录 开始-->48 <target name="error_file" xsi:type="File"49 layout="${newline}${longdate} ${level:uppercase=true} ${event-context:item=ErrorHead}${newline} ${message} 发生异常: ${onexception:${exception:format=tostring} ${newline} 堆栈信息为: ${stacktrace} ${newline}------------------------------------ "50 fileName="D:/CrmLog/Logs/${floderError}/${shortdate}.txt"51 archiveFileName="D:/CrmLog/archives/${floderError}/${shortdate}.{#####}.txt"52 archiveAboveSize="1024000"53 archiveNumbering="Sequence"54 concurrentWrites="true"55 keepFileOpen="false"56 encoding="utf-8"/>57 <!--错误记录 结束-->58 </targets>59 60 61 62 <rules>63 <!-- Add custom rule here -->64 <logger name="Microsoft.Xrm.DataProvider*" minLevel="Debug" writeTo="DataProviderExecutionETWTarget" final="true"/>65 <logger name="Microsoft.Xrm.DataPipeline" minLevel="Debug" writeTo="DataProviderExecutionETWTarget" final="true"/>66 <logger name="*" minLevel="Debug" writeTo="debug_info_file" />67 <logger name="*" levels="Error" writeTo="error_file" />68 69 <!-- Add default XrmTrace logging rule "*" here if you want to override in production-->70 71 </rules>72 </nlog>