.NET Core 服务诊断工具

一、Microsoft.Diagnostics.NETCore.Client 介绍:
 简介:

Microsoft.Diagnostics.NETCore.Client(也称为Diagnostics客户端库)是一个托管库,可让您与.NET Core运行时(Core CLR)进行交互以执行各种与诊断相关的任务,

例如:跟踪,请求转储或附加ICorProfiler 。使用此库,您可以编写针对特定情况定制的自己的诊断工具。

安装方式:

Install-Package Microsoft.Diagnostics.NETCore.Client
二、工具实现:
 1、创建项目:DiagnosticsTools(.NET 5.0 Winform项目)

添加包引用:

Install-Package Microsoft.Diagnostics.NETCore.Client
Install-Package Microsoft.Diagnostics.Tracing.TraceEvent 
  项目结构:

调整窗体界面如下:

2、获取当前所有.Net Core 3.0及以上的进程列表

复制代码
///
/// 获取进程状态:.Net Core 3.0及以上进程
///
private void PrintProcessStatus()
{
   //定位上次记录
int row = dgvPros.CurrentCell == null ? 0 : dgvPros.CurrentCell.RowIndex;
int col = dgvPros.CurrentCell == null ? 0 : dgvPros.CurrentCell.ColumnIndex;
var data = DiagnosticsClient.GetPublishedProcesses()
.Select(Process.GetProcessById)
.Where(process => process != null)
.Select(o => { return new { o.Id, o.ProcessName, o.StartTime, o.Threads.Count }; });

dgvPros.DataSource = data.ToList();
if (dgvPros.Rows.Count > row)
    dgvPros.CurrentCell = dgvPros.Rows[row].Cells[col];

}
复制代码
 3、获取当前进程基本信息:

复制代码
private string GetProInfo(Process info)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(“进程影象名:” + info.ProcessName + “\r\n”);
stringBuilder.Append(“进程ID:” + info.Id + “\r\n”);
stringBuilder.Append(“启动线程树:” + info.Threads.Count.ToString() + “\r\n”);
stringBuilder.Append(“CPU占用时间:” + info.TotalProcessorTime.ToString() + “\r\n”);
stringBuilder.Append(“线程优先级:” + info.PriorityClass.ToString() + “\r\n”);
stringBuilder.Append(“启动时间:” + info.StartTime.ToLongTimeString() + “\r\n”);
stringBuilder.Append(“专用内存:” + (info.PrivateMemorySize64 / 1024).ToString() + “K” + “\r\n”);
stringBuilder.Append(“峰值虚拟内存:” + (info.PeakVirtualMemorySize64 / 1024).ToString() + “K” + “\r\n”);
stringBuilder.Append(“峰值分页内存:” + (info.PeakPagedMemorySize64 / 1024).ToString() + “K” + “\r\n”);
stringBuilder.Append(“分页系统内存:” + (info.PagedSystemMemorySize64 / 1024).ToString() + “K” + “\r\n”);
stringBuilder.Append(“分页内存:” + (info.PagedMemorySize64 / 1024).ToString() + “K” + “\r\n”);
stringBuilder.Append(“未分页系统内存:” + (info.NonpagedSystemMemorySize64 / 1024).ToString() + “K” + “\r\n”);
stringBuilder.Append(“物理内存:” + (info.WorkingSet64 / 1024).ToString() + “K” + “\r\n”);
stringBuilder.Append(“虚拟内存:” + (info.VirtualMemorySize64 / 1024).ToString() + “K”);
return stringBuilder.ToString();
}
复制代码
 4、监听进程相关事件(CLR、Dynamic、Kernel等):

复制代码
///
/// 进程运行事件输出:CLR、性能计数器、动态处理(cpu使用率超过90%则抓取dump)
///
/// 进程id
/// cpu使用率
private void PrintRuntime(int processId, int threshold = 90)
{
if (!diagnosticsCache.ContainsKey(processId))
{
var providers = new List()
{
new EventPipeProvider(“Microsoft-Windows-DotNETRuntime”,EventLevel.Informational, (long)ClrTraceEventParser.Keywords.Default),
//性能计数器:间隔时间为1s
new EventPipeProvider(“System.Runtime”,EventLevel.Informational,(long)ClrTraceEventParser.Keywords.None,
new Dictionary<string, string>() {{ “EventCounterIntervalSec”, “1” }})
};

    DiagnosticsClient client = new DiagnosticsClient(processId);
    diagnosticsCache[processId] = client;
    using (EventPipeSession session = client.StartEventPipeSession(providers, false))
    {
        var source = new EventPipeEventSource(session.EventStream);

        source.Clr.All += (TraceEvent obj) =>
        {
            if (dgvPros.CurrentRow != null && obj.ProcessID.Equals(dgvPros.CurrentRow.Cells[0].Value))
            {
                string msg = $"Clr-{obj.EventName}-";
                if (obj.PayloadNames.Length > 0)
                {
                    foreach (var item in obj.PayloadNames)
                        msg += $"{item}:{ obj.PayloadStringByName(item)}-";
                }
                TextAppendLine(msg);
            }
        };
        source.Dynamic.All += (TraceEvent obj) =>
        {
            if (dgvPros.CurrentRow != null && obj.ProcessID.Equals(dgvPros.CurrentRow.Cells[0].Value))
            {
                string msg = $"Dynamic-{obj.EventName}-{string.Join("|", obj.PayloadNames)}";
        //性能计数器事件
        if (obj.EventName.Equals("EventCounters"))
                {
                    var payloadFields = (IDictionary<string, object>)(obj.PayloadByName(""));
                    if (payloadFields != null)
                        payloadFields = payloadFields["Payload"] as IDictionary<string, object>;

                    if (payloadFields != null)
                    {
                        msg = $"Dynamic-{obj.EventName}-{payloadFields["DisplayName"]}:{payloadFields["Mean"]}{payloadFields["DisplayUnits"]}";
                        TextAppendLine(msg);
                    }
            //如果CPU使用率超过90%抓取dump
            if (payloadFields != null && payloadFields["Name"].ToString().Equals("cpu-usage"))
                    {
                        double cpuUsage = Double.Parse(payloadFields["Mean"].ToString());
                        if (cpuUsage > (double)threshold)
                        {
                            client.WriteDump(DumpType.Normal, "/tmp/minidump.dmp");
                        }
                    }
                }
                else
                {
                    if (obj.PayloadNames.Length > 0)
                    {
                        foreach (var item in obj.PayloadNames)
                            msg += $"{item}:{ obj.PayloadStringByName(item)}-";
                    }
                    TextAppendLine(msg);
                }
            }
        };
        source.Kernel.All += (TraceEvent obj) =>
        {
            if (dgvPros.CurrentRow != null && obj.ProcessID.Equals(dgvPros.CurrentRow.Cells[0].Value))
            {
                string msg = $"Kernel-{obj.EventName}-{string.Join("|", obj.PayloadNames)}";
                TextAppendLine(msg);
            }
        };

        try
        {
            source.Process();
        }
        catch (Exception e)
        {
            string errorMsg = $"错误:{e}";
            TextAppendLine(errorMsg);
        }
    }
}

}
复制代码
 5、Dump抓取功能:

复制代码
///
/// 抓取Dmp文件
///
///
private void TriggerCoreDump(int processId)
{
saveFileDialog1.Filter = “Dump文件|*.dmp”;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
var client = new DiagnosticsClient(processId);
//Normal = 1,WithHeap = 2,Triage = 3,Full = 4
client.WriteDump(DumpType.Normal, saveFileDialog1.FileName, false);
}
}
复制代码
  参数说明:

转储类型。

Normal:仅包括捕获进程中所有现有线程的所有现有跟踪的堆栈跟踪所需的信息。有限的GC堆内存和信息。
WithHeap:包括GC堆和捕获进程中所有现有线程的堆栈跟踪所必需的信息。
Triage:仅包括捕获进程中所有现有线程的所有现有跟踪的堆栈跟踪所需的信息。有限的GC堆内存和信息。
Full:在此过程中包括所有可访问的内存。原始内存数据包含在末尾,因此可以直接映射初始结构,而无需原始内存信息。此选项可能会导致非常大的转储文件。
 6、生成进程指定事件内Trace文件

复制代码
///
/// 写入Trace文件
///
/// 进程ID
/// 指定时间范围(单位s)
private void TraceProcessForDuration(int processId, int duration)
{
saveFileDialog1.Filter = “Nettrace文件|*.nettrace”;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
var cpuProviders = new List()
{
new EventPipeProvider(“Microsoft-Windows-DotNETRuntime”, EventLevel.Informational, (long)ClrTraceEventParser.Keywords.Default),
new EventPipeProvider(“Microsoft-DotNETCore-SampleProfiler”, EventLevel.Informational, (long)ClrTraceEventParser.Keywords.None)
};
var client = new DiagnosticsClient(processId);
using (var traceSession = client.StartEventPipeSession(cpuProviders))
{
Task copyTask = Task.Run(async () =>
{
using (FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create, FileAccess.Write))
{
await traceSession.EventStream.CopyToAsync(fs);
}
});

        copyTask.Wait(duration * 1000);
        traceSession.Stop();
    }
}

}USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值