[netCore] how to capture data of coreprofiler then store data in sql server

預設coreprofiler使用記憶體存放200筆資料,如果你想要關閉監控功能,只需把circularBufferSize設定0即可,

由於記憶體資源不太可能都讓coreprofiler獨佔,所以我們必須將這些效能監控資料存放至SQL Server,

方便後續讓我們進行效能分析。

查看source code,我們知道InitializeConfigurationFromConfig() method,會從coreprofiler.json讀取設定。

https://github.com/teddymacn/CoreProfiler/blob/master/CoreProfiler/ProfilingSession.cs#L256

CoreProfilerMiddleware.cs這支讓我們知道,coreProfiler是透過middleware來呈現監控資料View(透過StringBuilder組html tag)。

https://github.com/teddymacn/CoreProfiler/blob/master/CoreProfiler.Web/CoreProfilerMiddleware.cs

 

大致看了source code後,看來所有profiler的資料都能新增到資料庫中的CoreProfiler資料表,

但我不想改現有controller中所有action的code,如下圖,

我原先都埋好每個階段的profiler,當然,你也可以每個階段接Timing物件,

處理Mapping後新增至SQL Server

像這種Infrastructure的處理,我比較喜歡統一底層來handle,開發人員不用額外判斷該相關功能是否有啟用,

一來不會破壞現有的code,二來也不會和現有business邏輯參雜一起變瀨尿牛丸

所以我打算透過ResultFilter來實現,相關code如下

@add a new module

[Serializable]
    [Table("CoreProfiler")]
    public class CoreProfilerModulecs
    {
        [Key]
        [Write(false)]
        public long Serial { get; set; }
        public string SessionId { get; set; }
        public string ParentId { get; set; }
        public string Machine { get; set; }
        public string Type { get; set; }
        public string CurrentId { get; set; }
        public string Name { get; set; }
        public Int64 Start { get; set; }
        public Int64 Duration { get; set; }
        public Int64 Sort { get; set; }
        public DateTime Started { get; set; }
        
    }

 

@add a new CoreProfilerResultFilter.cs (透過DI注入對應的Logger和Repository),

我這裡繼承非同步ResultFilter,這樣才不會影響server回應client時間

public class CoreProfilerResultFilter : Attribute, IAsyncResultFilter
    {
        private readonly ILogger<CoreProfilerResultFilter> _logger;
        private readonly ICoreProfilerRepository _coreProfilerRepository;
        public CoreProfilerResultFilter(ILogger<CoreProfilerResultFilter> logger, ICoreProfilerRepository coreProfilerRepository)
        {
            _logger = logger;
            _coreProfilerRepository = coreProfilerRepository;
        }
        public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            await next();  //after the action executes;
            var timingSession = ProfilingSession.Current.Profiler.GetTimingSession();
            if (timingSession != null)
            {
                string sessionId = timingSession.Id.ToString();
                List<CoreProfilerModulecs> coreProfilerModulecs = new List<CoreProfilerModulecs>();
                foreach (var timing in timingSession.Timings)
                {
                    long duration = 0;
                    if (timing.Name.ToLowerInvariant() == "root" && timing.DurationMilliseconds <= 0)
                        duration = timingSession.DurationMilliseconds;
                    coreProfilerModulecs.Add(new CoreProfilerModulecs
                    {
                        SessionId = sessionId,
                        ParentId = timing.ParentId.HasValue ? timing.ParentId.Value.ToString() : "",
                        Machine = timingSession.MachineName,
                        Type = timing.Type,
                        CurrentId = timing.Id.ToString(),
                        Name = timing.Name,
                        Start = timing.StartMilliseconds,
                        Duration = duration > 0 ? duration : timing.DurationMilliseconds,
                        Sort = timing.Sort,
                        Started = timing.Started
                    });
                }
                await _coreProfilerRepository.BulkInsertAsync(coreProfilerModulecs);
            }
 
           
        }
    }

Note:我這裡沒有處理Timing.Data物件資料,另外root的duration我使用session的duration。

 

@startup.cs統一設定

結果比對

SQL Server

 

View

參考

CoreProfiler

[netCore] MiddleWare

[netCore] Logging Framework

[C#][ASP.NET MVC]自訂Action Filter