当前位置: 首页 > news >正文

EF Core 与 MySQL:日志和调试详解

本文将详细讲解EF Core与MySQL的日志和调试,分为三个部分:EF Core日志配置、MySQL日志查看以及使用调试工具分析查询性能。

1. 配置 EF Core 日志

基本日志配置

// 在DbContext配置中启用日志记录
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{var connectionString = "server=localhost;database=efcoredb;user=root;password=yourpassword";optionsBuilder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)).EnableSensitiveDataLogging() // 记录参数值(仅开发环境).EnableDetailedErrors() // 提供更详细的错误信息(仅开发环境).LogTo(Console.WriteLine, LogLevel.Information) // 输出到控制台
        .LogTo(message => Debug.WriteLine(message), // 输出到调试输出
            LogLevel.Debug);
}

使用 ILoggerFactory(ASP.NET Core 应用)

// 在Program.cs或Startup.cs中配置
public void ConfigureServices(IServiceCollection services)
{services.AddDbContext<ApplicationDbContext>(options =>{var connectionString = Configuration.GetConnectionString("DefaultConnection");options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)).EnableSensitiveDataLogging(Environment.IsDevelopment()).EnableDetailedErrors(Environment.IsDevelopment()).UseLoggerFactory(LoggerFactory.Create(builder =>{builder.AddConsole().AddDebug().AddFilter(DbLoggerCategory.Database.Command.Name, LogLevel.Information);}));});
}

自定义日志过滤器

// 只记录执行时间超过100ms的查询
optionsBuilder.LogTo(message =>{if (message.Contains("CommandExecuted") && message.Contains("Elapsed")){var elapsedMatch = Regex.Match(message, @"Elapsed:(\d+)ms");if (elapsedMatch.Success && int.Parse(elapsedMatch.Groups[1].Value) > 100){Console.WriteLine($"慢查询: {message}");}}},LogLevel.Information
);

结构化日志记录

// 使用Serilog等结构化日志框架
Log.Logger = new LoggerConfiguration().MinimumLevel.Information().WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}").WriteTo.File("logs/efcore-.txt", rollingInterval: RollingInterval.Day).CreateLogger();services.AddDbContext<ApplicationDbContext>(options =>
{options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)).LogTo(Log.Logger.Information, LogLevel.Information).LogTo(Log.Logger.Warning, LogLevel.Warning).LogTo(Log.Logger.Error, LogLevel.Error);
});

2. 查看 MySQL 日志

启用和配置 MySQL 日志

-- 查看当前日志配置
SHOW VARIABLES LIKE '%log%';-- 启用通用查询日志(记录所有查询)
SET GLOBAL general_log = 'ON';
SET GLOBAL general_log_file = '/var/log/mysql/general.log';-- 启用慢查询日志
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
SET GLOBAL long_query_time = 1; -- 超过1秒的查询视为慢查询-- 启用二进制日志(用于复制和恢复)
SET GLOBAL log_bin = 'ON';-- 启用错误日志(通常默认开启)
SHOW VARIABLES LIKE 'log_error';

在 MySQL 配置文件中设置日志

# /etc/mysql/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
# 通用查询日志
general_log = 1
general_log_file = /var/log/mysql/general.log# 慢查询日志
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1# 错误日志
log_error = /var/log/mysql/error.log# 二进制日志
log_bin = /var/log/mysql/mysql-bin.log
expire_logs_days = 10
max_binlog_size = 100M

分析 MySQL 日志

# 查看慢查询日志
sudo tail -f /var/log/mysql/slow.log# 使用mysqldumpslow分析慢查询日志
sudo mysqldumpslow /var/log/mysql/slow.log# 按执行时间排序查看最慢的查询
sudo mysqldumpslow -s t /var/log/mysql/slow.log# 查看通用查询日志
sudo tail -f /var/log/mysql/general.log# 使用pt-query-digest分析查询(需要安装Percona Toolkit)
sudo pt-query-digest /var/log/mysql/slow.log

在应用程序中记录 MySQL 性能指标

// 创建性能监控服务
public class MySqlPerformanceMonitor
{private readonly ApplicationDbContext _context;private readonly ILogger<MySqlPerformanceMonitor> _logger;public MySqlPerformanceMonitor(ApplicationDbContext context, ILogger<MySqlPerformanceMonitor> logger){_context = context;_logger = logger;}public async Task MonitorQueryPerformanceAsync(Func<Task> databaseOperation, string operationName){var stopwatch = Stopwatch.StartNew();try{await databaseOperation();stopwatch.Stop();if (stopwatch.ElapsedMilliseconds > 1000) // 超过1秒的记录为警告
            {_logger.LogWarning("慢查询检测: {Operation} 耗时 {ElapsedMs}ms", operationName, stopwatch.ElapsedMilliseconds);}else if (stopwatch.ElapsedMilliseconds > 500) // 超过0.5秒的记录为信息
            {_logger.LogInformation("查询性能: {Operation} 耗时 {ElapsedMs}ms", operationName, stopwatch.ElapsedMilliseconds);}}catch (Exception ex){stopwatch.Stop();_logger.LogError(ex, "查询执行失败: {Operation} 耗时 {ElapsedMs}ms", operationName, stopwatch.ElapsedMilliseconds);throw;}}
}

3. 使用调试工具分析查询性能

使用 EF Core 的诊断工具

// 启用诊断监听器
DiagnosticListener.AllListeners.Subscribe(new EfCoreDiagnosticListener());public class EfCoreDiagnosticListener : IObserver<DiagnosticListener>
{public void OnNext(DiagnosticListener value){if (value.Name == DbLoggerCategory.Name){value.Subscribe(new EfCoreObserver());}}public void OnCompleted() { }public void OnError(Exception error) { }
}public class EfCoreObserver : IObserver<KeyValuePair<string, object>>
{public void OnNext(KeyValuePair<string, object> value){if (value.Key == RelationalEventId.CommandExecuted.Name){var command = (IDbCommand)value.Value.GetType().GetProperty("Command").GetValue(value.Value);var duration = (TimeSpan)value.Value.GetType().GetProperty("Duration").GetValue(value.Value);if (duration.TotalMilliseconds > 100){Debug.WriteLine($"慢查询: {command.CommandText} 耗时: {duration.TotalMilliseconds}ms");}}}public void OnCompleted() { }public void OnError(Exception error) { }
}

使用 Application Insights 监控

// 在Startup.cs中配置Application Insights
public void ConfigureServices(IServiceCollection services)
{services.AddApplicationInsightsTelemetry(Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]);services.AddDbContext<ApplicationDbContext>(options =>{options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)).EnableSensitiveDataLogging().AddApplicationInsightsDiagnostics(); // 如果支持的话
    });
}// 或者手动记录依赖跟踪
public async Task<List<Product>> GetProductsAsync()
{var operation = telemetryClient.StartOperation<DependencyTelemetry>("MySQL Query");operation.Telemetry.Type = "MySQL";operation.Telemetry.Data = "SELECT * FROM Products";try{var products = await _context.Products.ToListAsync();operation.Telemetry.Success = true;return products;}catch (Exception ex){operation.Telemetry.Success = false;telemetryClient.TrackException(ex);throw;}finally{telemetryClient.StopOperation(operation);}
}

使用 MiniProfiler

// 安装MiniProfiler.EntityFrameworkCore
// 在Startup.cs中配置
public void ConfigureServices(IServiceCollection services)
{services.AddMiniProfiler(options =>{options.RouteBasePath = "/profiler";options.ColorScheme = StackExchange.Profiling.ColorScheme.Auto;options.EnableMvcFilterProfiling = true;options.EnableMvcViewProfiling = true;options.TrackConnectionOpenClose = true;}).AddEntityFramework();
}public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{app.UseMiniProfiler();// ... 其他中间件
}// 在视图中添加MiniProfiler
@inject StackExchange.Profiling.MiniProfiler Profiler
@MiniProfiler.RenderIncludes(Profiler)

使用 JetBrains dotTrace 或 dotMemory

// 在代码中添加性能分析点
public async Task<List<Product>> GetExpensiveProductsAsync()
{// 使用JetBrains Profiler API(需要安装JetBrains.Profiler.Api包)
    JetBrains.Profiler.Api.MeasureProfiler.StartCollectingData();try{var products = await _context.Products.Where(p => p.Price > 100).Include(p => p.Category).ToListAsync();return products;}finally{JetBrains.Profiler.Api.MeasureProfiler.SaveData();}
}

使用 MySQL EXPLAIN 分析查询计划

// 在代码中执行EXPLAIN分析查询
public async Task<string> ExplainQueryAsync(IQueryable query)
{var sql = query.ToQueryString();var explainSql = $"EXPLAIN {sql}";using (var command = _context.Database.GetDbConnection().CreateCommand()){command.CommandText = explainSql;_context.Database.OpenConnection();using (var result = await command.ExecuteReaderAsync()){var explanation = new StringBuilder();while (await result.ReadAsync()){for (int i = 0; i < result.FieldCount; i++){explanation.AppendLine($"{result.GetName(i)}: {result.GetValue(i)}");}explanation.AppendLine("---");}return explanation.ToString();}}
}// 使用方式
var query = _context.Products.Where(p => p.Price > 100);
var explanation = await ExplainQueryAsync(query);
Console.WriteLine(explanation);

使用 Visual Studio 的调试工具

// 在Visual Studio中使用诊断工具
// 1. 打开"诊断工具"窗口(调试 -> 窗口 -> 显示诊断工具)
// 2. 开始调试并记录性能
// 3. 分析CPU使用率、内存分配和数据库查询// 使用条件断点调试特定查询
var products = _context.Products.Where(p => p.Price > 100) // 在这里设置条件断点:p.Price > 1000
    .ToList();// 使用即时窗口测试查询
// 在调试期间,可以在即时窗口中执行:
// _context.Products.Where(p => p.Price > 100).ToList()

创建自定义性能分析中间件

// ASP.NET Core中间件,用于记录所有数据库操作
public class QueryPerformanceMiddleware
{private readonly RequestDelegate _next;private readonly ILogger<QueryPerformanceMiddleware> _logger;public QueryPerformanceMiddleware(RequestDelegate next, ILogger<QueryPerformanceMiddleware> logger){_next = next;_logger = logger;}public async Task InvokeAsync(HttpContext context, ApplicationDbContext dbContext){var stopwatch = Stopwatch.StartNew();var originalQueryTrackingBehavior = dbContext.ChangeTracker.QueryTrackingBehavior;try{// 设置为NoTracking以提高性能,除非需要修改数据dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;await _next(context);}finally{stopwatch.Stop();dbContext.ChangeTracker.QueryTrackingBehavior = originalQueryTrackingBehavior;// 记录请求处理时间和数据库查询统计_logger.LogInformation("请求 {Method} {Path} 处理时间: {ElapsedMs}ms, 数据库查询次数: {QueryCount}",context.Request.Method, context.Request.Path, stopwatch.ElapsedMilliseconds,dbContext.GetQueryCount());}}
}// 扩展方法获取查询次数
public static class DbContextExtensions
{public static int GetQueryCount(this DbContext context){// 这种方法可能不准确,更好的方式是使用诊断监听器return 0; // 实际实现需要更复杂的方法
    }
}// 在Startup.cs中注册中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{app.UseMiddleware<QueryPerformanceMiddleware>();// ... 其他中间件
}

总结

本教程详细介绍了EF Core与MySQL的日志记录和调试技术,包括:

  1. 配置EF Core日志:

    • 基本日志配置和敏感数据记录

    • 使用ILoggerFactory集成ASP.NET Core日志系统

    • 自定义日志过滤器和结构化日志记录

  2. 查看MySQL日志:

    • 启用和配置各种MySQL日志(通用查询、慢查询、错误日志)

    • 分析MySQL日志以识别性能问题

    • 在应用程序中集成MySQL性能监控

  3. 使用调试工具分析查询性能:

    • EF Core诊断工具和监听器

    • Application Insights集成

    • MiniProfiler实时性能分析

    • JetBrains专业分析工具

    • MySQL EXPLAIN查询计划分析

    • Visual Studio调试工具

    • 自定义性能分析中间件

通过这些工具和技术,我们可以:

  • 识别和解决性能瓶颈

  • 优化数据库查询

  • 监控应用程序的健康状况

  • 诊断和解决生产环境中的问题

建议在开发环境中启用详细日志记录和性能分析,而在生产环境中则使用更保守的配置,只记录警告和错误,并定期检查慢查询日志以识别需要优化的查询。

http://www.hskmm.com/?act=detail&tid=8907

相关文章:

  • 使用镜像源解决github拉取代码问题 - GD
  • 日记
  • 主机连接虚拟机和hbase的命令
  • 类和面向对象
  • PHP转Go系列 | PHP8 这些新函数让你眼前一亮
  • 代码随想录算法训练营第二天 |209.长度最小的子数组,59. 螺旋矩阵 II
  • mac更新or安装homebrew失败
  • Typescript中闭包的原理 - 教程
  • CF2048H Kevin and Strange Operation
  • Hadoop本地库加载问题分析与解决方案
  • GO基础总结
  • Visual Studio 离线安装0x80131509
  • Oracle备份恢复:backup as copy保留文件名不变化,只更改路径名
  • 读书笔记:数据库中的预连接神器:位图连接索引
  • 故障处理:CRS无法随操作系统自动启动故障案例分享
  • 02020401 EF Core基础01-EF Core简介和开发环境搭建、实体类、配置类、继承DbContex的类、Migration包的使用
  • 专用通路方式
  • typeof()
  • 【未完成】2025.9 做题记录
  • 2025.8 做题记录
  • 关于 “Thinking Machines Lab首次发长文” 的一些知识的学习和补充
  • CF1630F 题解 | 网络流
  • 攻防世界-secret-galaxy-300 - xxx
  • 实用指南:LeetCode 面试经典 150_哈希表_单词规律(41_290_C++_简单)
  • 数据库
  • 代码随想录算法训练营第二天 | leetcode 209
  • mpv硬件解码
  • 2025.9.78——卷6-8选择
  • 关于pytorch的读书报告
  • Emacs 折腾日记(三十)——打造C++ IDE 续