湖南省网站建设_网站建设公司_留言板_seo优化
2026/1/17 18:52:34 网站建设 项目流程

 

using System;
using App.Metrics;
using App.Metrics.AspNetCore;
using App.Metrics.AspNetCore.Health;
using App.Metrics.Formatters.Prometheus;
using Microsoft.AspNetCore.Hosting;namespace Common.Metrics
{public static class Extensions{public static IWebHostBuilder UseAppMetrics(this IWebHostBuilder webHostBuilder)=> webHostBuilder.ConfigureMetricsWithDefaults((context, builder) =>{var metricsOptions = context.Configuration.GetOptions<MetricsOptions>("metrics");if (!metricsOptions.Enabled){return;}builder.Configuration.Configure(cfg =>{var tags = metricsOptions.Tags;if (tags == null){return;}tags.TryGetValue("app", out var app);tags.TryGetValue("env", out var env);tags.TryGetValue("server", out var server);cfg.AddAppTag(string.IsNullOrWhiteSpace(app) ? null : app);cfg.AddEnvTag(string.IsNullOrWhiteSpace(env) ? null : env);cfg.AddServerTag(string.IsNullOrWhiteSpace(server) ? null : server);foreach (var tag in tags){if (!cfg.GlobalTags.ContainsKey(tag.Key)){cfg.GlobalTags.Add(tag.Key, tag.Value);}}});if (metricsOptions.InfluxEnabled){builder.Report.ToInfluxDb(o =>{o.InfluxDb.Database = metricsOptions.Database;o.InfluxDb.BaseUri = new Uri(metricsOptions.InfluxUrl);o.InfluxDb.CreateDataBaseIfNotExists = true;o.FlushInterval = TimeSpan.FromSeconds(metricsOptions.Interval);});}}).UseHealth().UseHealthEndpoints().UseMetricsWebTracking().UseMetrics((context, options) =>{var metricsOptions = context.Configuration.GetOptions<MetricsOptions>("metrics");if (!metricsOptions.Enabled){return;}if (!metricsOptions.PrometheusEnabled){return;}options.EndpointOptions = endpointOptions =>{switch (metricsOptions.PrometheusFormatter?.ToLowerInvariant() ?? string.Empty){case "protobuf":endpointOptions.MetricsEndpointOutputFormatter =new MetricsPrometheusProtobufOutputFormatter();break;default:endpointOptions.MetricsEndpointOutputFormatter =new MetricsPrometheusTextOutputFormatter();break;}};});}
}

 

User AOP approach (Attribute / Interceptor base) to send hit count to InfluxDB and poll by Gafana

Benefit

Using attribute to encapsulate metric related operation so the team can have a uniform and elegant approach to achieve this.

Controller level

using Microsoft.AspNetCore.Mvc.Filters;
using System.Threading.Tasks;namespace Common.Metrics
{public class AppMetricCountAttribute : ActionFilterAttribute{private readonly string metricname;public IMetricRegistry metricRegistry { get; set; }public AppMetricCountAttribute(string MetricName) => metricname = MetricName;                 public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){metricRegistry = (IMetricRegistry)context.HttpContext.RequestServices.GetService(typeof(IMetricRegistry));metricRegistry.IncrementCount(metricname);return base.OnActionExecutionAsync(context, next);}}
}

Start up level

 Add Memory metric to Grafana

Goal  is to allow mimimum coding for subsystem to utilize the common feature to send system momory metric to INFLUX db and Displayed by Grafana

Demo

Extension

public static IServiceCollection AddGaugeMetric(this IServiceCollection service){GaugeOption option;using (var serviceprovider = service.BuildServiceProvider()){var configuration = serviceprovider.GetService<IConfiguration>();service.Configure<GaugeOption>(configuration.GetSection("gaugemetric"));option = configuration.GetOptions<GaugeOption>("gaugemetric");}//IF THESE TYPE ARE NOT FROM EXECUTING ASSEMBLY BUT FROM REFERENCED ASEMBLY//THEN ADDING TO SERVICE DI ONE BY ONE IS NECESSARY
            service.AddSingleton(option.GetType(), option); service.AddTransient<GaugeMetric>();service.AddSingleton<IHostedService, GaugeHostedService>();return service;}

GaugeMetric (Will be Inject to GaugeHostedService super class)

using App.Metrics;
using App.Metrics.Gauge;
using System.Diagnostics;namespace Common.Metrics
{public class GaugeMetric{private readonly IMetricsRoot root;private readonly GaugeOption option;public GaugeMetric(IMetricsRoot root, GaugeOption option){this.root = root;this.option = option;}public void SendGaugeData(){var processPhysicalMemoryGauge = new GaugeOptions{Name = option.name,MeasurementUnit = Unit.MegaBytes};var process = Process.GetCurrentProcess();root.Measure.Gauge.SetValue(processPhysicalMemoryGauge, process.WorkingSet64 / 1024.0 / 1024.0);}}
}

Utilized hosting service to trigger a contineous task is web hosted that run in configured interval

using Microsoft.Extensions.Logging;
using System;namespace Common.Metrics
{public class GaugeHostedService : HostedServiceTemplate{ILogger<GaugeHostedService> log;GaugeMetric gaugeMetric;GaugeOption option;public GaugeHostedService(ILogger<GaugeHostedService> log, GaugeMetric gaugeMetric, GaugeOption option) : base(option){this.log = log;this.gaugeMetric = gaugeMetric;this.option = option;}protected override void ExecuteAsync(object state){log.LogInformation(DateTime.Now.ToLongTimeString());gaugeMetric.SendGaugeData();}}
}

Super class - template design pattern

using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;namespace Common.Metrics
{public abstract class HostedServiceTemplate : IHostedService{private readonly CancellationTokenSource source;private int interval = 10;private Timer timer;private GaugeOption option;public HostedServiceTemplate(){ }protected HostedServiceTemplate(GaugeOption option){this.option = option;interval = option.delay;}public Task StartAsync(CancellationToken cancellationToken){//Create new cancel tokentimer = new Timer(ExecuteAsync, null, TimeSpan.Zero, TimeSpan.FromSeconds(interval));return Task.CompletedTask;}protected abstract void ExecuteAsync(object state);public Task StopAsync(CancellationToken cancellationToken){// Trigger source cancel to stop the on going timer?.Change(Timeout.Infinite, 0);return Task.CompletedTask;}}
}

 

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询