更新:
感謝您的澄清,我更好地理解您正在嘗試做什麼。您希望從IParameterInspector實現記錄的消息反映出Example.MyService是您的服務(如instanceType參數所指示的)的「Example.MyService.GetContacts」的調用站點,並且「GetContacts」是操作。您可以手動合成呼叫站點信息。你仍然會使用NLog的Logger.Log方法,並且你仍然會創建一個LogEventInfo對象。此外,您可以將「類」和「方法」存儲在LogEventInfo.Properties對象中。而不是根據instanceType(即服務)檢索記錄器(來自LogManager),根據參數檢查器的類型(您的情況爲NLogLogger)檢索記錄器。最後,您可以在NLog.config中添加一條附加規則(並將其應用於NLogLogger類型),以便規則具有不同的日誌記錄格式。您將在包含調用站點信息(存儲在LogEventInfo.Properties集合中)的日誌記錄格式中手動添加一個字段,其位置與其他日誌規則配置中的「真實」調用站點LayoutRenderer相同。
接下來我將發佈一個新版本的NLogLogger實現,它可以完成我上面描述的任務。
public class NLogLogger : IParameterInspector
{
private static readonly NLog.Logger logger = LogManager.GetCurrentClassLogger();
private void Log(Type instanceType, string operationName, string msg)
{
NLog.Logger serviceLogger = LogManager.GetLogger(
instanceType.FullName, instanceType);
//Create LogEventInfo with the Logger.Name from the logger associated with the service
LogEventInfo le = new LogEventInfo(LogLevel.Info, serviceLogger.Name, msg);
le.Properties.Add("fakecallsite", string.Format("{0}.{1}",instanceType.ToString(),operationName);
//Log the message using the parameter inspector's logger.
logger.Log(typeof(NLogLogger), le);
}
public object BeforeCall(string operationName, object[] inputs)
{
// Retrieve the service instance type for the logger then log the call.
OperationContext operationContext = OperationContext.Current;
Type instanceType = operationContext.InstanceContext
.GetServiceInstance().GetType();
Log(instanceType, operationName, "BeforeCall");
return instanceType;
}
public void AfterCall(
string operationName, object[] outputs,
object returnValue, object correlationState
)
{
if (correlationState is Type)
Log(correlationState, operationName, "AfterCall");
}
}
你的NLog.config將有類似這樣的規則。一條規則專門用於您的NLogLogger參數檢查器。它記錄到「f1」並且是「最終」規則,這意味着來自參數檢查器的記錄消息不會被任何其他規則記錄。另一個規則適用於所有其他記錄器。每個都記錄到不同的文件目標,但是兩個文件目標都寫入同一個文件(我認爲這是有效的)。關鍵是每個文件都有自己的佈局。
<logger name="Your.Full.NameSpace.NLogLogger" minlevel="*" writeTo="f1" final="true" />
<logger name="*" minlevel="*" writeTo="f2" />
你的目標和佈局看起來像這樣。我們正在定義一個變量,其值是EventPropertiesLayoutRenderer的值,它是我們存儲在LogEventInfo.Properties [「fakecallsite」]中的假呼叫站點。
<variable name="fakecallsite" value="${event-properties:fakecallsite}"/>
<variable name="f1layout" value="${longdate} | ${level} | ${logger} | ${fakecallsite} | ${message}"/>
<variable name="f2layout" value="${longdate} | ${level} | ${logger} | ${callsite} | ${message}"/>
<targets>
<target name="f1" xsi:type="File" layout="${f1layout}" fileName="${basedir}/${shortdate}.log" />
<target name="f2" xsi:type="File" layout="${f2layout}" fileName="${basedir}/${shortdate}.log" />
</targets>
請注意,我沒有試過,但我認爲它應該工作(或者應該是足夠接近,你可以得到它的工作)。一個限制是,由於我們正在計算假呼叫站點,因此我們不能使用真實呼叫站點LayoutRenderer來處理輸出中的fakecallsite字段的內容。如果這一點很重要,可以通過單獨存儲類和方法(在LogEventInfo.Properties中),然後在NLog.config中設置「fakecallsite」變量來包含類和/或方法來模擬。
END UPDATE
你的包裝應該使用Log方法。另外,您傳遞給NLog Logger.Log方法的類型應該是NLog Logger包裝器的類型,而不是服務實例類型的類型。您仍然可以使用您的服務實例的類型來檢索正確的Logger實例。它應該看起來像這樣:
public class NLogLogger : IParameterInspector
{
private void Log(Type instanceType, string operationName, string msg)
{
NLog.Logger logger = LogManager.GetLogger(
instanceType.FullName, instanceType);
//This is the key to preserving the call site in a wrapper. Create a LogEventInfo
//then use NLog's Logger.Log method to log the message, passing the type of your
//wrapper as the first argument.
LogEventInfo le = new LogEventInfo(LogLevel.Info, logger.Name, msg);
logger.Log(typeof(NLogLogger), le);
}
public object BeforeCall(string operationName, object[] inputs)
{
// Retrieve the service instance type for the logger then log the call.
OperationContext operationContext = OperationContext.Current;
Type instanceType = operationContext.InstanceContext
.GetServiceInstance().GetType();
Log(instanceType, operationName, "BeforeCall");
return instanceType;
}
public void AfterCall(
string operationName, object[] outputs,
object returnValue, object correlationState
)
{
if (correlationState is Type)
Log(correlationState, operationName, "AfterCall");
}
}
您需要使用Log方法。你不能編寫一個包裝器,只是委託給NLog的Info/Debug/Trace/etc方法。如果你再看看你發佈的鏈接(對於我發佈的回覆),你會看到我使用Log方法展示瞭如何編寫一個包裝器(保存呼叫站點信息)。 – wageoghe
我嘗試了不同的東西,其中還有'Log'方法和'LogEventInfo'類。問題是'NLogLogger'不是真正的包裝。請重新閱讀關於堆棧跟蹤的內容。 – nalply
你說得對,我誤解了你正在做的事。我會再添加一條建議。我不認爲這是一個好的,但它可能會有所幫助。 – wageoghe