1.获取正在运行的程序列表
在无侵入的情况下,我们首先需要获取到运行的dotnet程序,包括进程的名字和PID,在多个dotnet项目中,我们后边都会通过PID来对特定的程序进行诊断。 修改ConsoleApp的Program.cs如下,这里主要用到了 GetPublishedProcesses 方法。
class Program
{
static void Main(string[] args)
{
if (args.Any())
{
switch (args[0])
{
case “ps”: PrintProcessStatus(); break;
}
}
}
public static void PrintProcessStatus()
{
var processes = DiagnosticsClient.GetPublishedProcesses()
.Select(Process.GetProcessById)
.Where(process => process != null);
foreach (var process in processes)
{
Console.WriteLine($"ProcessId: {process.Id}");
Console.WriteLine($"ProcessName: {process.ProcessName}");
Console.WriteLine($"StartTime: {process.StartTime}");
Console.WriteLine($"Threads: {process.Threads.Count}");
Console.WriteLine();
Console.WriteLine();
}
}
}
修改完成后,我们用命令行启动项目,WebAPI 项目运行dotnet run命令 , 启动之后,ConsoleApp 再运行 dotnet run ps命令,ps 是我们传入的参数,我们可以在控制台上看到正在运行的进程信息,我们主要会用到pid。
2.获取 GC 信息
我们创建了一个 DiagnosticsClient的实例,在构造函数中传入了processId进程ID,然后开启了一个有关GC信息的会话,最后订阅了CLR相关的事件回调,输出了事件名称EventName到控制台。
static void Main(string[] args)
{
if (args.Any())
{
switch (args[0])
{
case “ps”: PrintProcessStatus(); break;
case “runtime”: PrintRuntime(int.Parse(args[1])); break;
}
}
}
public static void PrintRuntime(int processId)
{
var providers = new List()
{
new (“Microsoft-Windows-DotNETRuntime”,EventLevel.Informational, (long)ClrTraceEventParser.Keywords.GC)
};
var client = new DiagnosticsClient(processId);
using (var session = client.StartEventPipeSession(providers, false))
{
var source = new EventPipeEventSource(session.EventStream);
source.Clr.All += (TraceEvent obj) =>
{
Console.WriteLine(obj.EventName);
};
try
{
source.Process();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
接下来,我们修改一下WebAPI的代码,在控制器中的方法中创建了一个集合,并且添加了很多数据。
[HttpGet]
public IEnumerable Get()
{
List list = new ();
for (int i = 0; i < 1000000; i++)
{
list.Add(i.ToString());
}
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray();
}
同样,我们首先通过 dotnet run 命令启动WebAPI项目,然后 dotnet run ps 启动ConsoleApp项目,控制台会输出 webapi 项目的进程信息,我这里的pid是3832
然后在控制台项目中运行 dotnet run runtime 3832, runtime 和 3832 都是我们传入的参数, 然后开启一个新的命令行窗口,通过curl访问几次webapi的接口,当然你也可以在浏览器中访问,我们发现,在右边的控制台项目输出了GC的相关信息, 这里我们只输出了事件名,实际上我们可以拿到更多的数据信息。
3.获取异常信息
同样的,我们先修改WebApi项目,手动抛出一个异常。
[HttpGet]
public IEnumerable Get()
{
throw new Exception(“error”);
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray();
}
在控制台项目中,我们只需要改动一个Keywords 枚举,就是把 ClrTraceEventParser.Keywords.GC 改成 ClrTraceEventParser.Keywords.Exception,当然这里支持了其他更多的类型。
修改完成后,我们先启动 WebApi 项目,然后在ConsoleApp中先运行 dotnet run ps,查看webapi的进程id,然后再运行 dotnet run runtime 13600, 最后我们通过 curl 命令或者浏览器访问webapi的接口,同样,在右边的ConsoleApp中,输出了异常的相关事件信息。
在上面的代码中,我手动抛出一个异常,我们的诊断工具ConsoleApp是可以获取到相关的异常信息,那我用try,catch 把异常吃掉呢?它还能捕获到异常吗?
[HttpGet]
public IEnumerable Get()
{
try
{
Convert.ToInt32(“sss”);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray();
}
修改代码后,我们重新运行webapi和诊断工具ConsoleApp,访问api接口时,你会发现,就算我们用try,catch 吃掉了异常,它仍然会输出异常信息。
- 生成Dump文件
通过 Microsoft.Diagnostics.NETCore.Client 组件,我们可以很方便的为程序生生成Dump文件,然后可以用 windbg 工具来进行分析。
修改控制台项目ConsoleApp的Program.cs如下:
static void Main(string[] args)
{
if (args.Any())
{
switch (args[0])
{
case “ps”: PrintProcessStatus(); break;
case “runtime”: PrintRuntime(int.Parse(args[1])); break;
case “dump”: Dump(int.Parse(args[1])); break;
}
}
}
public static void Dump(int processId)
{
var client = new DiagnosticsClient(processId);
client.WriteDump(DumpType.Normal, @“mydump.dmp”, false);
}
修改完成后,启动webapi项目和控制台项目,在控制台项目中运行 dotnet run dump 13288 命令,它会在webapi的目录下,生成程序的dump文件
5.生成 Trace 文件
同样,我们可以很方便的生成 Trace 文件,它可以分析到CPU的函数执行耗时情况,它的格式是.nettrace, 你可以直接用VS 2017及以上或者 PerfView 工具打开。
修改控制台项目ConsoleApp的Program.cs如下:
static void Main(string[] args)
{
if (args.Any())
{
switch (args[0])
{
case “ps”: PrintProcessStatus(); break;
case “runtime”: PrintRuntime(int.Parse(args[1])); break;
case “dump”: Dump(int.Parse(args[1])); break;
case “trace”: Trace(int.Parse(args[1])); break;
}
}
}
public static void Trace(int processId)
{
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.Run(async () =>
{
using (FileStream fs = new FileStream(@“mytrace.nettrace”, FileMode.Create, FileAccess.Write))
{
await traceSession.EventStream.CopyToAsync(fs);
}
}).Wait(10 * 1000);
traceSession.Stop();
}
}
USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com