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>