.NET Core 集成 MiniProfiler性能分析工具

时间:2024-10-02 07:16:15

前言:

 在日常开发中,应用程序的性能是我们需要关注的一个重点问题。当然我们有很多工具来分析程序性能:如:Zipkin等;但这些过于复杂,需要单独搭建。

 MiniProfiler就是一款简单,但功能强大的应用新能分析工具;可以帮助我们定位:SQL性能问题、响应慢等问题。

 本篇文章将介绍MiniProfiler在Asp.Net Core中如何使用

一、MiniProfiler介绍

  MiniProfiler是一款针对.NET, Ruby, Go and Node.js的性能分析的轻量级程序。可以对一个页面本身,及该页面通过直接引用、Ajax、Iframe形式访问的其它页面进行监控,监控内容包括数据库内容,并可以显示数据库访问的SQL(支持EF、EF CodeFirst等 )。并且以很友好的方式展现在页面上。

    MiniProfiler官网:http://miniprofiler.com/

    MiniProfiler的一个特别有用的功能是它与数据库框架的集成。除了.NET原生的 DbConnection类,MiniProfiler还内置了对实体框架(Entity Framework)以及LINQ to SQL、RavenDb和MongoDB的支持。任何执行的Step都会包括当时查询的次数和所花费的时间。为了检测常见的错误,如N+1反模式,profiler将检测仅有参数值存在差异的多个查询。

二、MiniProfiler用法

 1、Nuget包安装:

//Mvc
Install-Package MiniProfiler.AspNetCore.Mvc
//EF分析添加
Install-Package MiniProfiler.EntityFrameworkCore
//Reids 缓存添加
Install-Package MiniProfiler.Providers.Redis

 2、配置MiniProfiler:修改Startup.cs

a) 注入MiniProfiler

public void ConfigureServices(IServiceCollection services)
{
    // ...其他配置...

    // 注入MiniProfiler
    services.AddMiniProfiler(options =>
    {
      //获取redis配置
        var redisOptions = App.GetOptions<RedisOptions>();
        if (redisOptions.Enable)
        options.Storage =
        new RedisStorage((ConnectionMultiplexer)App.GetService<IConnectionMultiplexer> 
        ());
       else
         options.Storage = new MemoryCacheStorage(App.GetService<IMemoryCache>(), 
       TimeSpan.FromMinutes(60));

        //访问地址路由根目录;默认为:/mini-profiler-resources
        options.RouteBasePath = "/profiler";
        //数据缓存时间
        (options.Storage as MemoryCacheStorage).CacheDuration = TimeSpan.FromMinutes(60);
        //sql格式化设置
        options.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter();
        //跟踪连接打开关闭
        options.TrackConnectionOpenClose = true;
        //界面主题颜色方案;默认浅色
        options.ColorScheme = StackExchange.Profiling.ColorScheme.Dark;
        //.net core 3.0以上:对MVC过滤器进行分析
        options.EnableMvcFilterProfiling = true;
        //对视图进行分析
        options.EnableMvcViewProfiling = true;

        //控制访问页面授权,默认所有人都能访问
        //options.ResultsAuthorize;
        //要控制分析哪些请求,默认说有请求都分析
        //options.ShouldProfile;

        //内部异常处理
        //options.OnInternalError = e => MyExceptionLogger(e);
    })
    // AddEntityFramework是要监控EntityFrameworkCore生成的SQL
    .AddEntityFramework();
}

b) 启用MiniProfiler

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IMemoryCache cache)
{
    // ...其他配置

    //该方法必须在app.UseEndpoints以前
    app.UseMiniProfiler();

    app.UseEndpoints(routes =>
    {
        // ...
    });
}

c) MVC项目:

 修改 _ViewImports.cshtml  

@using StackExchange.Profiling
@addTagHelper *, MiniProfiler.AspNetCore.Mvc

 将MiniProfiler添加到布局文件(Shared/_Layout.cshtml)中

<mini-profiler />

d) 运行效果:

三、 Swagger UI接入MiniProfiler

 使用步骤和前面大体一样

 1、下载Swagger页面:

请先在Github中下载对应版本的swagger页面:https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/src/Swashbuckle.AspNetCore.SwaggerUI/index.html

 2、添加到项目中,并设置index.html为:内嵌资源

  3、修改UseSwaggerUI中间件的配置

app.UseSwaggerUI(c =>
{
    //Blog.Core.Api 项目命名空间
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Blog.Core.API V1");
    c.IndexStream = () => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("Blog.Core.Api.index.html");
});

  4、获取MiniProfiler的html代码片段 

/// <summary>
/// 获取html片段
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("GetHtml")]
public IActionResult GetHtml()
{
    var html = MiniProfiler.Current.RenderIncludes(HttpContext);
    return Ok(html.Value);
}

<!--1、版本号要与nuget包一致;2、id不能为空-->
<script async="async" id="mini-profiler" src="/mini-profiler-resources/includes.min.js?v=4.2.22+4563a9e1ab" data-version="4.2.22+4563a9e1ab" data-path="/mini-profiler-resources/" data-current-id="f6b88311-015a-44ed-bde0-cdab4c2d0d9b" data-ids="ac204d24-e2df-486e-a135-8167336643b7,f6b88311-015a-44ed-bde0-cdab4c2d0d9b" data-position="Left" " data-scheme="Light" data-authorized="true" data-max-traces="15" data-toggle-shortcut="Alt+P" data-trivial-milliseconds="2.0" data-ignored-duplicate-execute-types="Open,OpenAsync,Close,CloseAsync"></script>

 5、在Swagger的Html中添加获取的MiniProfiler片段

<!--1、版本号要与nuget包一致;2、id不能为空-->
<script async="async" id="mini-profiler" src="/mini-profiler-resources/includes.min.js?v=4.2.22+4563a9e1ab" data-version="4.2.22+4563a9e1ab" data-path="/mini-profiler-resources/" data-current-id="f6b88311-015a-44ed-bde0-cdab4c2d0d9b" data-ids="ac204d24-e2df-486e-a135-8167336643b7,f6b88311-015a-44ed-bde0-cdab4c2d0d9b" data-position="Left" " data-scheme="Light" data-authorized="true" data-max-traces="15" data-toggle-shortcut="Alt+P" data-trivial-milliseconds="2.0" data-ignored-duplicate-execute-types="Open,OpenAsync,Close,CloseAsync"></script>

<!-- 加在页面顶部,下面代码是swagger 代码,可忽略 -->

<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!--极速模式-->
    <meta name="renderer" content="webkit" />
    <meta name="force-rendering" content="webkit" />
    <title>%(DocumentTitle)</title>
    <link href="./swagger-ui.css" rel="stylesheet">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="./swagger-ui.css">
    <link rel="icon" type="image/png" href="./logo/favicon-32x32.png" sizes="32x32" />
    <script src="js/jquery-3.3.1.min.js"></script>
    <style>
        .swagger-ui .opblock-summary-control:focus {
            outline: none
        }
        .swagger-ui .topbar .download-url-wrapper {
            display: flex;
            flex: 3;
            margin-bottom: 0px;
            justify-content: flex-end;
        }

        .swagger-ui .auth-container input[type=password], .swagger-ui .auth-container input[type=text] {
            min-width: 565px;
        }

        html {
            box-sizing: border-box;
            overflow-y: scroll;
        }

        *,
        *:before,
        *:after {
            box-sizing: inherit;
        }

        body {
            margin: 0;
            background: #fafafa;
        }

        .qqgroup {
            position: absolute;
            right: 0px;
            top: 0px;
        }

        .info {
            float: left;
            position: relative;
            width: 100%;
        }

        .download-contents {
            display: none;
        }
        /* 滚动槽 */
        ::-webkit-scrollbar {
            width: 9px;
            height: 9px;
        }

        ::-webkit-scrollbar-track {
            border-radius: 3px;
            background: rgba(0,0,0,0.06);
            -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.08);
        }
        /* 滚动条滑块 */
        ::-webkit-scrollbar-thumb {
            border-radius: 3px;
            background: rgba(0,0,0,0.12);
            -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.2);
        }
    </style>
    %(HeadContent)
</head>
<body style=" user-select: text;" >

 6、调用效果:

 

 如上图可以查看到所有请求路径及Sql操作耗时,那么如果需要监控指定代码块耗时如何实现呢

四、自定义标记:

   1、添加标记代码:

var miniPro = MiniProfiler.Current;
using (miniPro.Step("Add AuditLog"))
{
    //保存审计日志
    await _auditLogService.SaveAsync(auditInfo);
}

  2、取消监控方式:

using(MiniProfiler.Current.Ignore())
{
   //代码     
}

 3、当然MiniProfiler还有很多其他功能等待解锁:如监控ADO.NET执行耗时,需要使用:ProfileDBConnection 和 ProfileDBCommand对象:

总结:

 1、MiniProfiler使用非常简单
 2、功能满足日常中程序性能优化相关问题

其他: 

 MiniProfiler的监控列表地址:http://{xxx}/profiler/results-index