You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET Core中创建供BenchmarkFilter使用的CSV文件日志器?

实现自定义CSV日志器并注入到BenchmarkFilter

咱们一步一步来搞定这个需求,核心是要给BenchmarkFilter单独配置一个能输出CSV格式的日志实例,具体步骤如下:

1. 实现CSV格式的自定义日志提供程序

默认的日志组件没有直接支持CSV的选项,所以咱们得自己写一个专门生成CSV日志的提供程序和日志类。

首先创建CsvFileLoggerProvider,它负责创建日志实例并初始化CSV文件表头:

using Microsoft.Extensions.Logging;
using System.IO;
using System.Threading;

public class CsvFileLoggerProvider : ILoggerProvider
{
    private readonly string _filePath;
    private readonly object _lock = new object();

    public CsvFileLoggerProvider(string filePath)
    {
        _filePath = filePath;
        // 首次创建时写入CSV表头
        if (!File.Exists(filePath))
        {
            File.WriteAllText(filePath, "Timestamp,ActionFullName,ExecutionDurationMs\n");
        }
    }

    public ILogger CreateLogger(string categoryName)
    {
        return new CsvFileLogger(_filePath, _lock);
    }

    public void Dispose()
    {
        // 可添加文件流清理等逻辑
    }
}

然后实现CsvFileLogger,负责实际写入CSV格式的日志内容:

using Microsoft.Extensions.Logging;
using System;
using System.IO;

public class CsvFileLogger : ILogger
{
    private readonly string _filePath;
    private readonly object _lock;

    public CsvFileLogger(string filePath, object @lock)
    {
        _filePath = filePath;
        _lock = @lock;
    }

    public IDisposable BeginScope<TState>(TState state) => null;

    public bool IsEnabled(LogLevel logLevel)
    {
        // 只记录基准测试相关的信息级日志
        return logLevel == LogLevel.Information;
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        if (!IsEnabled(logLevel)) return;

        var logContent = formatter(state, exception);
        var timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff");
        // 处理字段中的逗号转义,避免破坏CSV格式
        var escapedContent = logContent.Replace(",", "\\,");
        var csvLine = $"{timestamp},{escapedContent}\n";

        // 线程安全写入文件,防止多请求并发写入冲突
        lock (_lock)
        {
            File.AppendAllText(_filePath, csvLine);
        }
    }
}

2. 注册自定义日志提供程序

根据你的.NET版本,在服务注册环节添加这个CSV日志提供程序:

如果你用的是.NET 6+(Program.cs):

var builder = WebApplication.CreateBuilder(args);

// 注册CSV日志提供程序,指定日志文件路径(比如存到wwwroot下的logs文件夹)
var logFilePath = Path.Combine(builder.Environment.WebRootPath, "logs", "action_benchmark.csv");
builder.Logging.AddProvider(new CsvFileLoggerProvider(logFilePath));

// 注册BenchmarkFilter为全局过滤器
builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add<BenchmarkFilter>();
});

// 其他服务配置...

var app = builder.Build();
// 中间件配置...
app.Run();

如果你用的是.NET 5及以前(Startup.cs):

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
    {
        options.Filters.Add<BenchmarkFilter>();
    });

    // 注册CSV日志提供程序
    services.AddLogging(loggingBuilder =>
    {
        var logFilePath = Path.Combine(Environment.WebRootPath, "logs", "action_benchmark.csv");
        loggingBuilder.AddProvider(new CsvFileLoggerProvider(logFilePath));
    });
}

3. 调整BenchmarkFilter注入日志并输出CSV字段

修改你的BenchmarkFilter,注入日志实例后,把Action名称、执行时长等数据按CSV格式输出:

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System.Diagnostics;

public class BenchmarkFilter : IActionFilter
{
    private readonly ILogger<BenchmarkFilter> _logger;
    private Stopwatch _stopwatch;

    public BenchmarkFilter(ILogger<BenchmarkFilter> logger)
    {
        _logger = logger;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        // 开始计时
        _stopwatch = Stopwatch.StartNew();
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        _stopwatch.Stop();
        // 获取Action的完整名称(控制器+Action)
        var actionFullName = $"{context.Controller.GetType().Name}.{context.ActionDescriptor.ActionName}";
        var durationMs = _stopwatch.ElapsedMilliseconds;

        // 直接输出CSV格式的日志内容,让日志器直接写入文件
        _logger.LogInformation("{ActionFullName},{DurationMs}", actionFullName, durationMs);
    }
}

4. 可选优化点

  • 日志滚动:如果日志文件过大,可以在CsvFileLoggerProvider里添加按天/按文件大小滚动日志的逻辑;
  • 异步写入:高并发场景下,把File.AppendAllText改成异步的await File.AppendAllTextAsync,配合SemaphoreSlim替代lock,性能会更好;
  • 字段标准化:如果Action名称可能包含特殊字符,可以进一步完善转义逻辑(比如用双引号包裹字段)。

这样配置完成后,BenchmarkFilter的基准测试数据就会自动写入你指定路径的CSV文件,格式清晰方便后续分析。

内容的提问来源于stack exchange,提问作者WhatTheDeuce

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:54:55