diff --git a/CoreProfilerExample.Common/CoreProfilerExample.Common.csproj b/CoreProfilerExample.Common/CoreProfilerExample.Common.csproj index fa71b7a..04296cf 100644 --- a/CoreProfilerExample.Common/CoreProfilerExample.Common.csproj +++ b/CoreProfilerExample.Common/CoreProfilerExample.Common.csproj @@ -6,4 +6,8 @@ enable + + + + diff --git a/CoreProfilerExample.Common/Extensions/MethodBaseExtension.cs b/CoreProfilerExample.Common/Extensions/MethodBaseExtension.cs new file mode 100644 index 0000000..6cc4101 --- /dev/null +++ b/CoreProfilerExample.Common/Extensions/MethodBaseExtension.cs @@ -0,0 +1,39 @@ +using CoreProfiler; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace CoreProfilerExample.Common.Extensions +{ + public static class MethodBaseExtension + { + public static IDisposable ProfilingStep(this MethodBase method, string? stepName = null) + { + if (stepName == null) + { + // 取得方法的類型物件 + var methodType = method.ReflectedType; + + // 取得類別的類型物件 + var classType = methodType?.ReflectedType ?? methodType; + + // 取出類別底下所有非同步類型的方法,比對出當前的方法類型 + var classMethodType = classType? + .GetMethods() + .Select(x => new + { + Method = x, + Attribute = x.GetCustomAttribute(), + }) + .FirstOrDefault(x => x.Attribute?.StateMachineType == methodType); + + var className = classType?.Name ?? "無法取得類別名稱"; + + var methodName = classMethodType?.Method.Name ?? method.Name ?? "無法取得方法名稱"; + + stepName = $"{classType?.Name}.{methodName}"; + } + + return ProfilingSession.Current.Step(stepName); + } + } +} diff --git a/CoreProfilerExample.Common/Options/CoreProfilerOption.cs b/CoreProfilerExample.Common/Options/CoreProfilerOption.cs new file mode 100644 index 0000000..8ad4cfd --- /dev/null +++ b/CoreProfilerExample.Common/Options/CoreProfilerOption.cs @@ -0,0 +1,61 @@ +using Newtonsoft.Json; + +namespace CoreProfilerExample.Common.Options +{ + public class CoreProfilerOption + { + /// + /// 資料保存上限(Session)。 + /// + [JsonProperty("circularBufferSize")] + public int CircularBufferSize { get; set; } = 200; + /// + /// 要過濾掉的項目。 + /// + [JsonProperty("filters")] + public IEnumerable Filters { get; set; } = [ + new CoreProfilerOptionFilter + { + Key = "/coreprofiler", + Value = "/coreprofiler", + Type = "CoreProfiler.ProfilingFilters.NameContainsProfilingFilter, CoreProfiler", + }, + new CoreProfilerOptionFilter + { + Key = "static files", + Value = "ico,jpg,js,css,svg,json,ttf,woff,woff2,eot", + Type = "CoreProfiler.ProfilingFilters.FileExtensionProfilingFilter, CoreProfiler", + }, + ]; + + public CoreProfilerOption Save(string filename) + { + var json = JsonConvert.SerializeObject(this, Formatting.Indented); + + File.WriteAllText(filename, json); + + return this; + } + + public static CoreProfilerOption UseCoreProfilerSetting() + { + var filename = Path.Combine(AppContext.BaseDirectory, "coreprofiler.json"); + + if (File.Exists(filename)) + { + try + { + var json = File.ReadAllText(filename); + + return JsonConvert.DeserializeObject(json); + } + catch + { + + } + } + + return new CoreProfilerOption().Save(filename); + } + } +} diff --git a/CoreProfilerExample.Common/Options/CoreProfilerOptionFilter.cs b/CoreProfilerExample.Common/Options/CoreProfilerOptionFilter.cs new file mode 100644 index 0000000..48b2bc4 --- /dev/null +++ b/CoreProfilerExample.Common/Options/CoreProfilerOptionFilter.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace CoreProfilerExample.Common.Options +{ + public class CoreProfilerOptionFilter + { + [JsonProperty("key")] + public string Key { get; set; } = null!; + [JsonProperty("value")] + public string Value { get; set; } = null!; + [JsonProperty("type")] + public string Type { get; set; } = null!; + } +} diff --git a/CoreProfilerExample.Repository/Implements/WeatherForecastRepository.cs b/CoreProfilerExample.Repository/Implements/WeatherForecastRepository.cs index 65d929d..494fb17 100644 --- a/CoreProfilerExample.Repository/Implements/WeatherForecastRepository.cs +++ b/CoreProfilerExample.Repository/Implements/WeatherForecastRepository.cs @@ -1,5 +1,7 @@ -using CoreProfilerExample.Repository.Interfaces; +using CoreProfilerExample.Common.Extensions; +using CoreProfilerExample.Repository.Interfaces; using CoreProfilerExample.Repository.Models.DataModels; +using System.Reflection; using static CoreProfilerExample.Common.Constants.WeatherConstant; namespace CoreProfilerExample.Repository.Implements @@ -8,12 +10,15 @@ namespace CoreProfilerExample.Repository.Implements { public Task> GetAsync(int days) { - return Task.Run(() => days > 0 ? Enumerable.Range(1, days).Select(index => new WeatherForecastDataModel + using (MethodBase.GetCurrentMethod()?.ProfilingStep()) { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = WeatherSummaries[Random.Shared.Next(WeatherSummaries.Length)] - }) : []); + return Task.Run(() => days > 0 ? Enumerable.Range(1, days).Select(index => new WeatherForecastDataModel + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = WeatherSummaries[Random.Shared.Next(WeatherSummaries.Length)] + }) : []); + } } } } diff --git a/CoreProfilerExample.Service/Extensions/MapperExtension.cs b/CoreProfilerExample.Service/Extensions/MapperExtension.cs index b597b76..9db7a1a 100644 --- a/CoreProfilerExample.Service/Extensions/MapperExtension.cs +++ b/CoreProfilerExample.Service/Extensions/MapperExtension.cs @@ -1,10 +1,5 @@ using CoreProfilerExample.Repository.Models.DataModels; using CoreProfilerExample.Service.Models.Dtos; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace CoreProfilerExample.Service.Extensions { diff --git a/CoreProfilerExample.Service/Implements/WeatherService.cs b/CoreProfilerExample.Service/Implements/WeatherService.cs index 46e5555..dc7d52c 100644 --- a/CoreProfilerExample.Service/Implements/WeatherService.cs +++ b/CoreProfilerExample.Service/Implements/WeatherService.cs @@ -1,21 +1,28 @@ -using CoreProfilerExample.Repository.Interfaces; +using CoreProfilerExample.Common.Extensions; +using CoreProfilerExample.Repository.Interfaces; using CoreProfilerExample.Service.Extensions; using CoreProfilerExample.Service.Interfaces; using CoreProfilerExample.Service.Models.Dtos; using CoreProfilerExample.Service.Models.ParameterDtos; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Reflection; namespace CoreProfilerExample.Service.Implements { - public class WeatherService(IWeatherForecastRepository weatherForecast) : IWeatherService + public class WeatherService : IWeatherService { + public WeatherService(IWeatherForecastRepository weatherForecast) + { + this.weatherForecast = weatherForecast; + } + + private readonly IWeatherForecastRepository weatherForecast = null!; + public Task GetWeatherForecastAsync(GetWeatherForecastParameterDto parameterDto) { - return weatherForecast.GetAsync(parameterDto.ForecastDays).ToDtoAsync(); + using (MethodBase.GetCurrentMethod()?.ProfilingStep()) + { + return weatherForecast.GetAsync(parameterDto.ForecastDays).ToDtoAsync(); + } } } } diff --git a/CoreProfilerExample.Service/Models/Dtos/GetWeatherForecastDto.cs b/CoreProfilerExample.Service/Models/Dtos/GetWeatherForecastDto.cs index 1ed21fb..452b529 100644 --- a/CoreProfilerExample.Service/Models/Dtos/GetWeatherForecastDto.cs +++ b/CoreProfilerExample.Service/Models/Dtos/GetWeatherForecastDto.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace CoreProfilerExample.Service.Models.Dtos +namespace CoreProfilerExample.Service.Models.Dtos { public class GetWeatherForecastDto { diff --git a/CoreProfilerExample.Service/Models/Dtos/GetWeatherForecastItemDto.cs b/CoreProfilerExample.Service/Models/Dtos/GetWeatherForecastItemDto.cs index 79a36b7..0565875 100644 --- a/CoreProfilerExample.Service/Models/Dtos/GetWeatherForecastItemDto.cs +++ b/CoreProfilerExample.Service/Models/Dtos/GetWeatherForecastItemDto.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace CoreProfilerExample.Service.Models.Dtos +namespace CoreProfilerExample.Service.Models.Dtos { public class GetWeatherForecastItemDto { diff --git a/CoreProfilerExample.Service/Models/ParameterDtos/GetWeatherForecastParameterDto.cs b/CoreProfilerExample.Service/Models/ParameterDtos/GetWeatherForecastParameterDto.cs index 15e89b0..6a90bf2 100644 --- a/CoreProfilerExample.Service/Models/ParameterDtos/GetWeatherForecastParameterDto.cs +++ b/CoreProfilerExample.Service/Models/ParameterDtos/GetWeatherForecastParameterDto.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace CoreProfilerExample.Service.Models.ParameterDtos +namespace CoreProfilerExample.Service.Models.ParameterDtos { public class GetWeatherForecastParameterDto { diff --git a/CoreProfilerExample.sln b/CoreProfilerExample.sln index 75a48a1..96579f7 100644 --- a/CoreProfilerExample.sln +++ b/CoreProfilerExample.sln @@ -11,6 +11,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreProfilerExample.Service EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreProfilerExample.Common", "CoreProfilerExample.Common\CoreProfilerExample.Common.csproj", "{DDD6FCC3-454E-42CB-94D0-23A7EA57D039}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "方案項目", "方案項目", "{5C1FF8FA-0F30-4581-8173-320356AFD2CC}" + ProjectSection(SolutionItems) = preProject + README.md = README.md + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/CoreProfilerExample/Controllers/WeatherController.cs b/CoreProfilerExample/Controllers/WeatherController.cs index db44914..8ad5c66 100644 --- a/CoreProfilerExample/Controllers/WeatherController.cs +++ b/CoreProfilerExample/Controllers/WeatherController.cs @@ -1,9 +1,11 @@ +using CoreProfilerExample.Common.Extensions; using CoreProfilerExample.Infrastructure.Extensions; using CoreProfilerExample.Models.Parameters; using CoreProfilerExample.Models.ViewModels; using CoreProfilerExample.Service.Interfaces; using Microsoft.AspNetCore.Mvc; using System.Net; +using System.Reflection; namespace CoreProfilerExample.Controllers { @@ -17,13 +19,16 @@ namespace CoreProfilerExample.Controllers [ProducesResponseType(typeof(ExceptionViewModel), (int)HttpStatusCode.BadRequest)] public async Task GetWeatherForecastAsync(GetWeatherForecastParameter parameter) { - try + using (MethodBase.GetCurrentMethod()?.ProfilingStep()) { - return Ok(await weather.GetWeatherForecastAsync(parameter.ToDto()).ToViewModel()); - } - catch (Exception ex) - { - return BadRequest(ex.ToViewModel()); + try + { + return Ok(await weather.GetWeatherForecastAsync(parameter.ToDto()).ToViewModel()); + } + catch (Exception ex) + { + return BadRequest(ex.ToViewModel()); + } } } } diff --git a/CoreProfilerExample/CoreProfilerExample.csproj b/CoreProfilerExample/CoreProfilerExample.csproj index 0b8764a..7118ec8 100644 --- a/CoreProfilerExample/CoreProfilerExample.csproj +++ b/CoreProfilerExample/CoreProfilerExample.csproj @@ -7,6 +7,7 @@ + diff --git a/CoreProfilerExample/Infrastructure/Extensions/DependencyInjectionExtension.cs b/CoreProfilerExample/Infrastructure/Extensions/DependencyInjectionExtension.cs index cf85aed..b8eda56 100644 --- a/CoreProfilerExample/Infrastructure/Extensions/DependencyInjectionExtension.cs +++ b/CoreProfilerExample/Infrastructure/Extensions/DependencyInjectionExtension.cs @@ -1,4 +1,6 @@ -using CoreProfilerExample.Repository.Implements; +using CoreProfiler.Web; +using CoreProfilerExample.Common.Options; +using CoreProfilerExample.Repository.Implements; using CoreProfilerExample.Repository.Interfaces; using CoreProfilerExample.Service.Implements; using CoreProfilerExample.Service.Interfaces; @@ -18,5 +20,14 @@ namespace CoreProfilerExample.Infrastructure.Extensions services.AddScoped(); return services; } + + public static IApplicationBuilder UseCoreProfiler(this IApplicationBuilder app) + { + CoreProfilerOption.UseCoreProfilerSetting(); + + app.UseCoreProfiler(true); + + return app; + } } } diff --git a/CoreProfilerExample/Program.cs b/CoreProfilerExample/Program.cs index c03b524..f7e249a 100644 --- a/CoreProfilerExample/Program.cs +++ b/CoreProfilerExample/Program.cs @@ -22,4 +22,8 @@ app.UseAuthorization(); app.MapControllers(); +#region CoreProfilerExample +app.UseCoreProfiler(); +#endregion + app.Run(); diff --git a/CoreProfilerExampleResource/LastestProfilingResult.JPG b/CoreProfilerExampleResource/LastestProfilingResult.JPG new file mode 100644 index 0000000..6d5ccb8 Binary files /dev/null and b/CoreProfilerExampleResource/LastestProfilingResult.JPG differ diff --git a/CoreProfilerExampleResource/LastestProfilingResultDetail.JPG b/CoreProfilerExampleResource/LastestProfilingResultDetail.JPG new file mode 100644 index 0000000..a920d55 Binary files /dev/null and b/CoreProfilerExampleResource/LastestProfilingResultDetail.JPG differ diff --git a/README.md b/README.md index b9d1bd3..7de1725 100644 --- a/README.md +++ b/README.md @@ -1 +1,119 @@ -# CoreProfilerExample \ No newline at end of file +## CoreProfiler + +```Shell +NUGET INSTALL coreprofiler -Version 1.1.4 +``` + +ΩSw϶ӮɡC + +򥻤kpU: + +```C# +var stepName = $"{class_name}.{method_name}"; + +using (ProfilingSession.Current.Step(stepName)) +{ + // ݭnpɪ{Xq +} +``` + +ѩjOϥάۦPҫA]dҤѤ@XRkAzLϮgoOPkW١C + +```C# +// ./CoreProfilerExample.Common/Extensions/MethodBaseExtension.cs + +public static IDisposable ProfilingStep(this MethodBase method, string? stepName = null) +{ + if (stepName == null) + { + // ok + var methodType = method.ReflectedType; + + // oO + var classType = methodType?.ReflectedType ?? methodType; + + // XOUҦDPBkAXek + var classMethodType = classType? + .GetMethods() + .Select(x => new + { + Method = x, + Attribute = x.GetCustomAttribute(), + }) + .FirstOrDefault(x => x.Attribute?.StateMachineType == methodType); + + var className = classType?.Name ?? "LkoOW"; + + var methodName = classMethodType?.Method.Name ?? method.Name ?? "LkokW"; + + stepName = $"{classType?.Name}.{methodName}"; + } + + return ProfilingSession.Current.Step(stepName); +} +``` + +XR MethodBase OA}o̥iHۦMwO_nJstepNameѼơAYSJh|zLϮg޳NoOPkW١A@Ӯɪ϶qW١C + +Ϯg: zLMethodBaseӨokTypeAAoOTypeA쥻o˴NiHϥNameӨoOPkW١AkYDPBAh|Xn\ŪW١A]ݭnAHUާ@Өo\ŪW: + +```C# +var classMethodType = classType? + .GetMethods() + .Select(x => new + { + Method = x, + Attribute = x.GetCustomAttribute(), + }) + .Where(x => x.Attribute?.StateMachineType == methodType) + .FirstOrDefault(); +``` + +QOTypeo䩳UҦkAAzLkType覡okMethodInfoANiHϥNameӨoŪkW٤FC + +XRk򥻨ϥΤkpU: + +```C# +using (MethodBase.GetCurrentMethod()?.ProfilingStep()) +{ + // ݭnpɪ{Xq +} + +using (MethodBase.GetCurrentMethod()?.ProfilingStep("qW")) +{ + // ݭnpɪ{Xq +} +``` + +## CoreProfiler.Web + +```Shell +NUGET INSTALL CoreProfiler.Web -Version 1.1.4 +``` + +NCӶqnlܪ{X]˦nAAӦwˤKdApU: + +```C# +// ./CoreProfilerExample/Infrastructure/Extensions/DependencyInjectionExtension.cs + +public static IApplicationBuilder UseCoreProfiler(this IApplicationBuilder app) +{ + CoreProfilerOption.UseCoreProfilerSetting(); + + app.UseCoreProfiler(true); + + return app; +} +``` + +ϥCoreProfilerOption.UseCoreProfilerSetting()kӲGUIһݪ]wѼƫAϥapp.UseCoreProfiler(true)`Jε{AѼtrueܨC@ӬqO_nUdO_LqC + +Ұʫs /nanoprofiler/view T{O_ҥΦ\C + +pU: + +![LastestProfilingResult](CoreProfilerExampleResource/LastestProfilingResult.JPG) + +ԲӦpU: + +![LastestProfilingResultDetail](CoreProfilerExampleResource/LastestProfilingResultDetail.JPG) \ No newline at end of file