簡體   English   中英

每個 Http 請求的去中心化 NLog 目標

[英]Decentralized NLog Target per Http request

語境

我正在使用 NLog 和 .NET Web API 2 框架。

服務器是一個多租戶環境,其中錯誤被記錄到各個客戶端數據庫中。 我有一個 NLog.config 文件,其中包含一個 DatabaseTarget 但(故意)缺少一個連接字符串屬性。 在請求開始時,客戶端的連接字符串被獲取並以編程方式添加到數據庫目標,以便可以將錯誤記錄到客戶端的數據庫中。

執行 Web Api 操作后,我會清除連接字符串,以便后續請求不會記錄到錯誤的數據庫中。 這適用於連續請求。

問題

對服務器的並發請求都試圖一次更改數據庫目標的連接字符串。 平均錯誤記錄到最后在數據庫目標上設置的數據庫。

是否可以將 NLog 實例或至少將日志記錄目標隔離到單個請求? 如果沒有,我將如何實現這一目標?

注意:要求在 NLog.config 文件中配置數據庫目標(連接字符串除外),以便可以在不更改代碼的情況下修改其查詢。 我仍然對不可能實現的解決方案感興趣,例如。 以編程方式創建數據庫目標。

代碼

NLog.config 文件

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <targets>
    <!--
      The logdatabase target's connectionString is
      added programmatically.
    -->
    <target name="logdatabase"
            xsi:type="Database"
            dbProvider="odbc">
      <commandText>
        <!-- super secret query is here -->
      </commandText>
      <!-- super secret parameters are here -->
    </target>
  </targets>

  <rules>
    <!-- rule is added programmatically so that there are no logging attempts before a connection string is added -->
  </rules>
</nlog>

注入連接字符串代碼片段(在每個請求開始時調用)

/// <summary>
/// Set up NLog to log to the database.
/// <param name="connectionString">Database to log to</param>
/// </summary>
private void SetUpDatabaseLogging(string connectionString)
{
    DatabaseTarget databaseTarget = LogManager.Configuration.FindTargetByName<DatabaseTarget>("logdatabase");
    databaseTarget.ConnectionString = connectionString;

    // Add rule if it does not exist already
    if (!DatabaseRuleExists("logdatabase"))
    {
        LoggingRule logDatabase = new LoggingRule("*", LogLevel.Debug, databaseTarget);
        LogManager.Configuration.LoggingRules.Add(logDatabase);
    }

    LogManager.ReconfigExistingLoggers();
}

/// <summary>
/// Check if a rule exists that uses the specified target
/// </summary>
/// <returns></returns>
private bool DatabaseRuleExists(string targetName)
{
    bool ruleExists = false;

    foreach (LoggingRule rule in LogManager.Configuration.LoggingRules)
    {
        if (rule.Targets.Where(target => target.Name == targetName).Count() > 0)
        {
            ruleExists = true;
            break;
        }
    }

    return ruleExists;
}

刪除連接字符串和日志記錄規則的過濾器(在每個控制器上使用)

/// <summary>
/// Clean up log database connection after request
/// </summary>
public class LogCleanUpFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        base.OnActionExecuted(actionExecutedContext);

        // Remove connection string from logging target.
        DatabaseTarget databaseTarget = LogManager.Configuration.FindTargetByName<DatabaseTarget>("logdatabase");
        databaseTarget.ConnectionString = null;

        // Remove database rule. Rule must not persist between requests
        // because we are logging to client database.
        foreach (LoggingRule rule in LogManager.Configuration.LoggingRules)
        {
            if (rule.Targets.Where(target => target.Name == "logdatabase").Count() > 0)
            {
                LogManager.Configuration.LoggingRules.Remove(rule);
                break;
            }
        }

        LogManager.ReconfigExistingLoggers();
    }
}

我正在使用當前的類記錄器進行記錄

private Logger logger = LogManager.GetCurrentClassLogger();
logger.Error("I'm a naughty function");

謝謝你們。 對不起,文字牆。

正如您所注意到的,在多線程環境中全局更改事物是很棘手的。

在這種情況下,最好將連接字符串存儲在綁定到線程的上下文中。 最好的選擇是“映射診斷邏輯上下文”( ${mdlc} ),它綁定到一個線程並且它是異步子線程。

它還使很多事情變得更容易,因為您不必動態更改規則。

用法:

  1. 創建數據庫目標並使用 MDLC 作為連接字符串

    在您的 nlog.config 中:

     <target xsi:type="Database" name="target1" connectionString="${mdlc:myConnectionString}" .. />
  2. 在請求的開頭設置連接字符串。

    (這是所有需要的 C#)

     MappedDiagnosticsLogicalContext.Set("myConnectionString", "server=...user=..");

就這樣。 不需要LogManager.ReconfigExistingLoggers ,循環/更改 NLog 規則。

查看 MDLC 的文檔

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM