ASP.NET CORE 에서 AppMetrics 사용 시 어떻게 표시되는지 알아보기 위한 테스트

 

AppMetrics 는 제니퍼나 핀포인트같은 APM 은 아니고...

모니터링 할만한 데이터를 좀 더 쉽게 구하여 저장할 수 있도록 도와주는 라이브러리.

 

grafana, slack, influxdb, prometheus, elsticsearch, http, socket, console, appinsights, text file 로 연동 가능

(https://www.app-metrics.io/reporting/)

 

 

 

 

- 환경

AppMetrics 3.1.0 (https://www.app-metrics.io/)

InfluxDB 1.7.7

Grafana 6.2.5

.Net Core 2.2 - ASP.NET API 프로젝트 (https://yamoe.tistory.com/528)

 

 

# 참고.

AppMetrics 메뉴얼(https://www.app-metrics.io/) 및 Github 의 최신 샘플인 Sample.V2(https://github.com/AppMetrics/Samples.V2) 는

AppMetrics 2.0 기준으로 되어있어 3.1.0과 인터페이스 차이가 있으나 아직 문서가 없음.

 

 

 

 

- 구성

ASP.NET의 AppMetrics가 데이터들을 InfluxDB 에 저장해주고

Grafana가 InfluxDB를 조회하여 그래프를 그려줌

 

.NET(AppMetrics) ------> InfluxDB <------- Grafana

 

 

 

 

- 테스트한 ASP.NET Core API 소스

SampleProject.zip
다운로드

 

 

 

 

 

 

- InfluxDB 설치

-- 설치

다운로드 페이지 : https://portal.influxdata.com/downloads/

InfluxDB 1.7.7 windows 64bit 버전 다운로드 (https://dl.influxdata.com/influxdb/releases/influxdb-1.7.7_windows_amd64.zip)

C:\apm\influxdb 에 압축해제

 

-- 설정

C:\apm\influxdb\influxdb.conf

[meta]

dir = "C:\\apm\\influxdb\\meta"

[data]

dir = "C:\apm\\influxdb\\data"

wal-dir = "C:\apm\\influxdb\\wal"

 

-- 실행

C:\apm\influxdb>influxd -config ./influxdb.conf

 

-- 접속

C:\apm\influxdb>influx -host 127.0.0.1 -port 8086

Connected to http://localhost:8086 version 1.7.7

InfluxDB shell version: 1.7.7

 
 
 
 
- AppMetrics 3.1.0 설치 (nuget)
 
visual studio 2017 에서 SampleProject 를 열고 (SampleProject : https://yamoe.tistory.com/528 의 샘플 프로젝트 사용)
"도구 - NuGet 패키지 관리자(N) - 패키지 관리자 콘솔(O)" 에서 설치
(이것저것 여러가지 설치했음)
 
PM> Install-Package App.Metrics -Version 3.1.0
PM> Install-Package App.Metrics.AspNetCore -Version 3.1.0
PM> Install-Package App.Metrics.AspNetCore.Mvc -Version 3.1.0
PM> Install-Package App.Metrics.AspNetCore.Tracking -Version 3.1.0
PM> Install-Package App.Metrics.AspNetCore.Endpoints -Version 3.1.0
PM> Install-Package App.Metrics.AspNetCore.Hosting -Version 3.1.0
PM> Install-Package App.Metrics.AspNetCore.Health -Version 3.1.0
PM> Install-Package App.Metrics.Reporting.InfluxDB -Version 3.1.0
PM> Install-Package App.Metrics.Reporting.TextFile -Version 3.1.0
PM> Install-Package App.Metrics.Reporting.Console -Version 3.1.0
PM> Install-Package App.Metrics.Formatters.InfluxDB -Version 3.1.0
PM> Install-Package App.Metrics.Health.Reporting.Metrics -Version 3.1.0
PM> Install-Package App.Metrics.Formatters.Ascii -Version 3.1.0
PM> Install-Package App.Metrics.Formatters.Json -Version 3.1.0
 
설치 후 visual studio 재시작
 
 
 
 
- 소스 수정 : Program.cs
일부 설정은 appsettings.json 에도 할 수 있으나 코드로만 설정 진행.
Program.cs 혹은 Startup.cs 에 설정하는 두가지 방식이 있으나 Program.cs 에만 설정하는 방식으로 진행.
첨부한 소스 파일엔 Health Check을 Report 하기 위해(influxdb 저장) 설정 방법이 약간 다름.
// 주요 모듈
using App.Metrics;
using App.Metrics.AspNetCore;
using App.Metrics.AspNetCore.Health;
using App.Metrics.Formatters.InfluxDB;
using App.Metrics.Formatters.Json;
using App.Metrics.Filtering;
using App.Metrics.Health;
using App.Metrics.Reporting.InfluxDB;

.... 생략 ....

        public static IWebHostBuilder CreateWebHostBuilder(string[] args)
        {
            return WebHost.CreateDefaultBuilder(args)
                .ConfigureHealthWithDefaults(
                    options =>
                    {
 // Health 체크 설정
                    }
                )
                .ConfigureMetricsWithDefaults(
                    builder =>
                    {
                        builder.Report.ToInfluxDb(
                            options =>
                            {
         // InfluxDB 관련 설정
     }
                        );
                    }
                )

                .UseMetricsWebTracking() // metrics 수집
                .UseHealth()    // Enable Report Health
                .UseMetricsEndpoints()  // Metrics 관련 Endpoint 노출 : /metrics, /metrics-text, /env
                .UseHealthEndpoints()   // Health 관련 Endpoint 노출 : /health, /ping
                .UseMetrics()   // Enable Metrics
                .... 생략 ....
        }
    }
}
 
- 소스 작성 : Registry.cs
custom metrics 를 입력해보기위해 작성.
Gauges, Counter, Meters, Histograms, Timers, Apdex 제공됨
HIstogram과 Timer 만 설정
using App.Metrics;
using App.Metrics.Histogram;
using App.Metrics.Timer;

namespace SampleProject
{
    public class Registry
    {
        // influxdb 의 hist__hist1 테이블(measurement) 에 기록됨
        public static HistogramOptions Hist1 = new HistogramOptions
        {
            Context = "hist",
            Name = "hist1",
            MeasurementUnit = Unit.Bytes            
        };

        // influxdb 의 hist__hist2 테이블(measurement) 에 기록됨
        public static HistogramOptions Hist2 = new HistogramOptions
        {
            Context = "hist",
            Name = "hist2",
            MeasurementUnit = Unit.Bytes            
        };

        // influxdb 의 timer__timer1 테이블(measurement) 에 기록됨
        public static TimerOptions Timer1 = new TimerOptions
        {
            Context = "Timer",
            Name = "Timer1",
            MeasurementUnit = Unit.Requests,
            DurationUnit = TimeUnit.Milliseconds,
            RateUnit = TimeUnit.Milliseconds
        };

    }
}
 
- 소스 수정 : ValuesController.cs

Registry.cs 의 metrics 사용하기 위해 endpoint 에 코드 삽입

namespace SampleProject.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        public static Random Rnd { get; } = new Random();
        private readonly IMetrics _metrics;

        public ValuesController(IMetrics metrics)
        {
            // DI(의존성 주입)
            _metrics = metrics ?? throw new ArgumentNullException(nameof(metrics));
        }

        ... 생략 ...

        // GET api/values/5
        [HttpGet("{id}")]
        public ActionResult<string> Get(int id)
        {
            _metrics.Measure.Histogram.Update(Registry.Hist1, new MetricTags("key1", "value1"), Rnd.Next(1, 500));
            _metrics.Measure.Histogram.Update(Registry.Hist2, new MetricTags("key2", "value2"), Rnd.Next(1, 500));
            _metrics.Measure.Timer.Time(Registry.Timer1, Rnd.Next(1,100).ToString());

            return "value";
        }

        ... 생략 ...

 

 

- 자동생성된 Endpoint 확인

 

-- Health Endpoints

UseHealthEndpoints() 코드에 의해 /health, /ping 엔드포인트가 자동 생성됨.

 

--- http://localhost/ping 응답 결과

pong

 

--- http://localhost/health 응답 결과

{
 // 코드상 추가한 커스텀 필드
 "healthy": {
 "DatabaseConnected": "Database Connection OK"
 },

 // 원본
 "status": "Healthy"
}

 

-- Metrics Endpoints

.UseMetricsEndpoints() 코드에 의해 /metrics, /metrics-text, /env 엔드포인트가 자동 생성됨.

 

--- http://localhost/metrics 응답 결과

...더보기

 

{  
   "timestamp":"2019-08-06T07:39:30.5193067Z",
   "contexts":[  
      {  
         "context":"Application.HttpRequests",
         "apdexScores":[  
            {  
               "name":"Apdex|server:DESKTOP-AA,app:SampleProject,env:development",
               "frustrating":0,
               "sampleSize":6,
               "satisfied":6,
               "score":1,
               "tolerating":0,
               "tags":{  
                  "server":"DESKTOP-AA",
                  "app":"SampleProject",
                  "env":"development"
               }
            }
         ],
         "counters":[  
            {  
               "name":"Active|server:DESKTOP-AA,app:SampleProject,env:development",
               "unit":"Active Requests",
               "count":1,
               "items":[],
               "tags":{  
                  "server":"DESKTOP-AA",
                  "app":"SampleProject",
                  "env":"development"
               }
            }
         ],
         "gauges":[ ],
         "histograms":[ ],
         "meters":[ ],
         "timers":[  
            {  
               "name":"Transactions|server:DESKTOP-AA,app:SampleProject,env:development",
               "unit":"req",
               "activeSessions":2,
               "count":6,
               "durationUnit":"ms",
               "histogram":{  
                  "lastValue":44.2118,
                  "max":203.1857,
                  "mean":44.658915653236896,
                  "median":44.2118,
                  "min":0.36779999999999996,
                  "percentile75":44.2118,
                  "percentile95":51.0657,
                  "percentile98":203.1857,
                  "percentile99":203.1857,
                  "percentile999":203.1857,
                  "sampleSize":6,
                  "stdDev":35.03442755073794,
                  "sum":304.0806
               },
               "rate":{  
                  "fifteenMinuteRate":29.25993514138139,
                  "fiveMinuteRate":19.342214039341584,
                  "meanRate":1.8059570115079762,
                  "oneMinuteRate":1.6505125267202088
               },
               "rateUnit":"min",
               "tags":{  
                  "server":"DESKTOP-AA",
                  "app":"SampleProject",
                  "env":"development"
               }
            }
         ]
      },
      {  
         "context":"Application",
         "apdexScores":[ ],
         "counters":[ ],
         "gauges":[ ],
         "histograms":[ ],
         "meters":[ ],
         "timers":[ ]
      },
      {  
         "context":"Application.Health",
         "apdexScores":[ ],
         "counters":[ ],
         "gauges":[  
            {  
               "name":"Results|health_check_name:DatabaseConnected,server:DESKTOP-AA,app:SampleProject,env:development",
               "unit":"items",
               "value":1,
               "tags":{  
                  "health_check_name":"DatabaseConnected",
                  "server":"DESKTOP-AA",
                  "app":"SampleProject",
                  "env":"development"
               }
            },
            {  
               "name":"Score|server:DESKTOP-AA,app:SampleProject,env:development",
               "unit":"Health Score",
               "value":1,
               "tags":{  
                  "server":"DESKTOP-AA",
                  "app":"SampleProject",
                  "env":"development"
               }
            }
         ],
         "histograms":[ ],
         "meters":[ ],
         "timers":[ ]
      },
      {  
         "context":"appmetrics.internal",
         "apdexScores":[ ],
         "counters":[  
            {  
               "name":"report_success|server:DESKTOP-AA,app:SampleProject,env:development",
               "unit":"items",
               "count":1,
               "items":[  
                  {  
                     "count":1,
                     "item":"App.Metrics.Reporting.InfluxDB.InfluxDbMetricsReporter",
                     "percent":100
                  }
               ],
               "tags":{  
                  "server":"DESKTOP-AA",
                  "app":"SampleProject",
                  "env":"development"
               }
            }
         ],
         "gauges":[ ],
         "histograms":[ ],
         "meters":[ ],
         "timers":[ ]
      }
   ]
}

 

--- http://localhost/metrics-text 응답 결과

...더보기
# TIMESTAMP: 637006741983695184
# MEASUREMENT: [Application.HttpRequests] Apdex
# TAGS:
                 server = DESKTOP-AA
                    app = SampleProject
                    env = development
                  mtype = apdex
                   unit = result
# FIELDS:
                samples = 9
                  score = 1
              satisfied = 9
             tolerating = 0
            frustrating = 0
--------------------------------------------------------------
# TIMESTAMP: 637006741983695184
# MEASUREMENT: [Application.HttpRequests] Active
# TAGS:
                 server = DESKTOP-AA
                    app = SampleProject
                    env = development
                  mtype = counter
                   unit = Active Requests
# FIELDS:
                  value = 1
--------------------------------------------------------------
# TIMESTAMP: 637006741983695184
# MEASUREMENT: [Application.HttpRequests] Transactions
# TAGS:
                 server = DESKTOP-AA
                    app = SampleProject
                    env = development
                  mtype = timer
                   unit = req
               unit_dur = ms
              unit_rate = min
# FIELDS:
            count.meter = 9
                 rate1m = 1.04030877914232
                 rate5m = 9.37132333699066
                rate15m = 22.8314473155257
              rate.mean = 1.26407352957666
                samples = 9
                   last = 9.378
             count.hist = 9
                    sum = 314.9379
                    min = 0.3678
                    max = 203.1857
                   mean = 5.80460754651153
                 median = 9.378
                 stddev = 8.84548253284347
                   p999 = 51.0657
                    p99 = 44.2118
                    p98 = 9.378
                    p95 = 9.378
                    p75 = 9.378
--------------------------------------------------------------
# TIMESTAMP: 637006741983695184
# MEASUREMENT: [Application.Health] Results
# TAGS:
      health_check_name = DatabaseConnected
                 server = DESKTOP-AA
                    app = SampleProject
                    env = development
                  mtype = gauge
                   unit = items
# FIELDS:
                  value = 1
--------------------------------------------------------------
# TIMESTAMP: 637006741983695184
# MEASUREMENT: [Application.Health] Score
# TAGS:
                 server = DESKTOP-AA
                    app = SampleProject
                    env = development
                  mtype = gauge
                   unit = Health Score
# FIELDS:
                  value = 1
--------------------------------------------------------------
# TIMESTAMP: 637006741983695184
# MEASUREMENT: [appmetrics.internal] report_success  items
# TAGS:
                 server = DESKTOP-AA
                    app = SampleProject
                    env = development
                   item = App.Metrics.Reporting.InfluxDB.InfluxDbMetricsReporter
                  mtype = counter
                   unit = items
# FIELDS:
                  total = 0
                percent = 0
--------------------------------------------------------------
# TIMESTAMP: 637006741983695184
# MEASUREMENT: [appmetrics.internal] report_success
# TAGS:
                 server = DESKTOP-AA
                    app = SampleProject
                    env = development
                  mtype = counter
                   unit = items
# FIELDS:
                  value = 0
--------------------------------------------------------------

 

 

--- http://localhost/env 응답 결과

...더보기
          Assembly Name = SampleProject
       Assembly Version = 1.0.0.0
  Framework Description = .NET Core 4.6.27817.03
             Local Time = 2019-08-06T16:36:11.1830+09:00
           Machine Name = DESKTOP-AA
        OS Architecture = X64
            OS Platform = WINDOWS
             OS Version = Microsoft Windows 10.0.18362
   Process Architecture = X64

 

 

 

 

- influxdb 저장되고 있는 데이터 확인

api 를 몇번 호출한 후 influxdb에 잘 저장되었는지 확인.

 

아래 주소를 3~4번씩 호출

http://localhost/api/values

http://localhost/api/values/1

http://localhost/api/values/asdf            <--- 400 고의적 유발

 

 

influx cli 확인

...더보기
C:\apm\influxdb>influx
Connected to http://localhost:8086 version 1.7.7
InfluxDB shell version: 1.7.7

> show databases
name: databases
name
----
_internal
AspDotNet

> use AspDotNet
Using database AspDotNet

> show measurements
name: measurements
name
----
application.health__results
application.health__score
application.httprequests__active
application.httprequests__apdex
application.httprequests__transactions
appmetrics.internal__report_success
appmetrics.internal__report_success__items
hist__hist1
hist__hist2
timer__timer1


> select * from "hist__hist1" order by time desc limit 3
name: hist__hist1
time                app           count.hist env         key1   last max mean median min mtype     p75 p95 p98 p99 p999 samples server          stddev sum unit
----                ---           ---------- ---         ----   ---- --- ---- ------ --- -----     --- --- --- --- ---- ------- ------          ------ --- ----
1565079034481917300 SampleProject 1          development value1 328  328 328  328    328 histogram 328 328 328 328 328  1       DESKTOP-L0EG94H 0      328 B
1565079033465981300 SampleProject 1          development value1 328  328 328  328    328 histogram 328 328 328 328 328  1       DESKTOP-L0EG94H 0      328 B
1565079032459731300 SampleProject 1          development value1 328  328 328  328    328 histogram 328 328 328 328 328  1       DESKTOP-L0EG94H 0      328 B


> select * from "hist__hist2" order by time desc limit 3
name: hist__hist2
time                app           count.hist env         key2   last max mean median min mtype     p75 p95 p98 p99 p999 samples server          stddev sum unit
----                ---           ---------- ---         ----   ---- --- ---- ------ --- -----     --- --- --- --- ---- ------- ------          ------ --- ----
1565079034481917300 SampleProject 1          development value2 149  149 149  149    149 histogram 149 149 149 149 149  1       DESKTOP-L0EG94H 0      149 B
1565079033465981300 SampleProject 1          development value2 149  149 149  149    149 histogram 149 149 149 149 149  1       DESKTOP-L0EG94H 0      149 B
1565079032459731300 SampleProject 1          development value2 149  149 149  149    149 histogram 149 149 149 149 149  1       DESKTOP-L0EG94H 0      149 B

> select * from "timer__timer1" order by time desc limit 3
name: timer__timer1
time                app           count.hist count.meter env         last    max     mean    median  min     mtype p75     p95     p98     p99     p999    rate.mean             rate15m              rate1m               rate5m               samples server          stddev sum     unit unit_dur unit_rate
----                ---           ---------- ----------- ---         ----    ---     ----    ------  ---     ----- ---     ---     ---     ---     ----    ---------             -------              ------               ------               ------- ------          ------ ---     ---- -------- ---------
1565079034481917300 SampleProject 1          1           development 20.9639 20.9639 20.9639 20.9639 20.9639 timer 20.9639 20.9639 20.9639 20.9639 20.9639 0.0000686206224211598 0.000197790077858784 0.000169296344978123 0.000193443220096401 1       DESKTOP-L0EG94H 0      20.9639 req  ms       ms
1565079033465981300 SampleProject 1          1           development 20.9639 20.9639 20.9639 20.9639 20.9639 timer 20.9639 20.9639 20.9639 20.9639 20.9639 0.0000737638277855976 0.000198891969600979 0.000184008882925865 0.000196694290764324 1       DESKTOP-L0EG94H 0      20.9639 req  ms       ms
1565079032459731300 SampleProject 1          1           development 20.9639 20.9639 20.9639 20.9639 20.9639 timer 20.9639 20.9639 20.9639 20.9639 20.9639 0.0000796773367448619 0.000198891969600979 0.000184008882925865 0.000196694290764324 1       DESKTOP-L0EG94H 0      20.9639 req  ms       ms


> select * from "application.httprequests__transactions" order by time desc limit 3
name: application.httprequests__transactions
time                app           count.hist count.meter env         last    max      mean             median  min     mtype p75      p95      p98      p99      p999     rate.mean        rate15m          rate1m           rate5m           samples server          stddev           sum      unit unit_dur unit_rate
----                ---           ---------- ----------- ---         ----    ---      ----             ------  ---     ----- ---      ---      ---      ---      ----     ---------        -------          ------           ------           ------- ------          ------           ---      ---- -------- ---------
1565079034481917300 SampleProject 2          2           development 54.1359 161.4807 107.405764547511 54.1359 54.1359 timer 161.4807 161.4807 161.4807 161.4807 161.4807 7.76122503227651 23.7348093430541 20.3155613973747 23.2131864115681 2       DESKTOP-L0EG94H 53.6708904991289 215.6166 req  ms       min
1565079033465981300 SampleProject 2          2           development 54.1359 161.4807 107.405764547511 54.1359 54.1359 timer 161.4807 161.4807 161.4807 161.4807 161.4807 8.30717709017904 23.8670363521175 22.0810659511038 23.6033148917188 2       DESKTOP-L0EG94H 53.6708904991289 215.6166 req  ms       min
1565079032459731300 SampleProject 2          2           development 54.1359 161.4807 107.405764547511 54.1359 54.1359 timer 161.4807 161.4807 161.4807 161.4807 161.4807 8.92911727401431 23.8670363521175 22.0810659511038 23.6033148917188 2       DESKTOP-L0EG94H 53.6708904991289 215.6166 req  ms       min
>

 

 

 

 

 

 

- Grafana 설치

 

-- 다운로드

다운로드 페이지 : https://grafana.com/grafana/download?platform=windows

Grafana 6.2.5 windows 64 bit zip file 버전 다운로드 (https://dl.grafana.com/oss/release/grafana-6.2.5.windows-amd64.zip)

C:\apm\grafana 에 압축해제

 

-- 설정

C:\apm\grafana\conf 의 sample.ini 를 custom.ini 로 복사 후 원하는 설정 변경 (복사만하고 그냥 진행함)

 

-- 실행

C:\apm\grafana\bin>grafana-server

 

-- 접속

http://localhost:3000

admin/admin

 

-- dashboard 참고

https://grafana.com/grafana/dashboards?search=app+metrics

https://grafana.com/grafana/dashboards/2125

 

 

 

 

- Grafana Dashboard 설치

 

OAuth2 는 사용하지 않으므로 Web Dashboard 만 설치 및 확인.

Web Dashboard : https://grafana.com/grafana/dashboards/2125

OAuth2 Dashboard : https://grafana.com/grafana/dashboards/2137

 

 

-- InfluxDB Data Source 생성

 

 

 

 

 

-- Web Dashboard 설치

 

 

 

 

 

 

-- 플러그인 설치 및 grafana 재시작

Web Dashboard 가 pie chart 를 사용하고 있어서 설치 함.

 

플러그인 설치

C:\apm\grafana\bin>grafana-cli plugins install grafana-piechart-panel

 

grafana 종료 후 재시작

C:\apm\grafana\bin>grafana-server

 

 

 

 

- Grafana Dashboard 확인

 

 

 

 

# 데이터가 별로 안나오는 상황은?

에러나 POST 등의 요청이 있어야 기록되기 때문에 호출된 적이 없으면 그래프가 안나올 수 있음.

 

 

아래 주소를 3~4번씩 호출 후 다시 확인

http://localhost/api/values

http://localhost/api/values/1

http://localhost/api/values/asdf            <--- 400 고의적 유발

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

- 기타

* dotnet-architecture/PerformanceMonitor

https://github.com/dotnet-architecture/PerformanceMonitor

 

* microsoft/ApplicationInsights-aspnetcore

https://github.com/microsoft/ApplicationInsights-aspnetcore

 

* Prometheus With Aspnetcore

https://www.kimsereylam.com/dotnetcore/csharp/prometheus/2019/01/11/prometheus-with-aspnetcore.html

 

 

'C#' 카테고리의 다른 글

숫자 범위 추출 및 확장  (0) 2021.11.03
C# LZ4  (0) 2021.10.20
dictionary 에 action 매핑시 instance method 호출 방법  (0) 2021.10.16
[ASP.NET] .net core 2.2 singleton controller  (0) 2019.08.29
[asp.net] asp.net core 2.2 iis 게시  (0) 2019.08.03
C#  (0) 2011.05.15
WPF  (0) 2011.05.08
C# 기초  (0) 2010.12.19