add prometheus integration for node and netcore

This commit is contained in:
marcel-dempers 2019-08-26 22:43:46 +10:00
parent 8bb97ec9e7
commit 17394dde98
14 changed files with 910 additions and 27 deletions

View File

@ -0,0 +1,758 @@
{
"__inputs": [],
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "5.0.4"
}
],
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": null,
"links": [],
"panels": [
{
"collapsed": true,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": 20,
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 11,
"x": 0,
"y": 1
},
"id": 22,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "irate(dotnet_request_operations_total[2m])",
"format": "time_series",
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Request per Second",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 11,
"x": 11,
"y": 1
},
"id": 24,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "rate(dotnet_request_duration_seconds_sum[2m]) / rate(dotnet_request_duration_seconds_count[2m])",
"format": "time_series",
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Request Duration",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"title": ".NET Core",
"type": "row"
},
{
"collapsed": true,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 1
},
"id": 14,
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 11,
"x": 0,
"y": 2
},
"id": 17,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "irate(node_request_operations_total[2m])",
"format": "time_series",
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Request per Second",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 11,
"x": 11,
"y": 2
},
"id": 18,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "rate(node_request_duration_seconds_sum[2m]) / rate(node_request_duration_seconds_count[2m])",
"format": "time_series",
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Request Duration",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"title": "NodeJS",
"type": "row"
},
{
"collapsed": true,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 2
},
"id": 8,
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 11,
"x": 0,
"y": 2
},
"id": 10,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "irate(go_request_operations_total[2m])",
"format": "time_series",
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Request per Second",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 11,
"x": 11,
"y": 2
},
"id": 12,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "rate(go_request_duration_seconds_sum[2m]) / rate(go_request_duration_seconds_count[2m])",
"format": "time_series",
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Request Duration",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"title": "Golang",
"type": "row"
},
{
"collapsed": true,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 3
},
"id": 6,
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 8,
"w": 11,
"x": 0,
"y": 3
},
"id": 4,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "rate(python_request_duration_seconds_sum[2m]) / rate(python_request_duration_seconds_count[2m])",
"format": "time_series",
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Request Duration",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 8,
"w": 11,
"x": 11,
"y": 3
},
"id": 2,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "irate(python_request_operations_total[2m])",
"format": "time_series",
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Request per Second (Python)",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"title": "Python",
"type": "row"
}
],
"schemaVersion": 16,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-5m",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "Application Telemetry (Prometheus)",
"uid": "pvXvovKWz",
"version": 2
}

View File

@ -6,28 +6,28 @@ services:
container_name: go-application container_name: go-application
image: go-application image: go-application
ports: ports:
- "80:80" - "80:5000"
python-application: python-application:
build: build:
context: ./python-application context: ./python-application
container_name: python-application container_name: python-application
image: python-application image: python-application
ports: ports:
- "81:80" - "81:5000"
dotnet-application: dotnet-application:
build: build:
context: ./dotnet-application context: ./dotnet-application
container_name: dotnet-application container_name: dotnet-application
image: dotnet-application image: dotnet-application
ports: ports:
- "82:80" - "82:5000"
nodejs-application: nodejs-application:
build: build:
context: ./nodejs-application context: ./nodejs-application
container_name: nodejs-application container_name: nodejs-application
image: nodejs-application image: nodejs-application
ports: ports:
- "83:80" - "83:5000"
prometheus: prometheus:
container_name: prometheus-svc container_name: prometheus-svc
image: prom/prometheus image: prom/prometheus

View File

@ -1,16 +1,34 @@
using System; using System;
using System.Diagnostics;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
using Prometheus;
namespace work.Pages namespace work.Pages
{ {
public class IndexModel : PageModel public class IndexModel : PageModel
{ {
private static readonly Counter ProcessedJobCount = Metrics
.CreateCounter("dotnet_request_operations_total", "The total number of processed requests");
public void OnGet() public void OnGet()
{ {
var sw = Stopwatch.StartNew();
sw.Stop();
ProcessedJobCount.Inc();
var histogram =
Metrics
.CreateHistogram(
"dotnet_request_duration_seconds",
"Histogram for the duration in seconds.",
new[] { 0.02, 0.05, 0.1, 0.15, 0.2, 0.5, 0.8, 1 },
"GET",
"/");
histogram
.Observe(sw.Elapsed.TotalSeconds);
} }
} }

View File

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Prometheus;
namespace work namespace work
{ {
@ -52,7 +53,7 @@ namespace work
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseStaticFiles(); app.UseStaticFiles();
app.UseCookiePolicy(); app.UseCookiePolicy();
app.UseMetricServer();
app.UseMvc(); app.UseMvc();
} }
} }

View File

@ -10,6 +10,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App"/> <PackageReference Include="Microsoft.AspNetCore.App"/>
<PackageReference Include="prometheus-net.AspNetCore" Version="3.1.4"/>
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" /> <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
</ItemGroup> </ItemGroup>

View File

@ -25,6 +25,6 @@ RUN apk update && apk upgrade && \
WORKDIR /go/src/app WORKDIR /go/src/app
COPY --from=builder /go/src/app/myapp /go/src/app/myapp COPY --from=builder /go/src/app/myapp /go/src/app/myapp
EXPOSE 80 EXPOSE 5000
CMD ["./myapp"] CMD ["./myapp"]

View File

@ -46,6 +46,6 @@ func main() {
}) })
http.Handle("/metrics", promhttp.Handler()) http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":80", nil) http.ListenAndServe(":5000", nil)
} }

View File

@ -8,6 +8,7 @@
"start": "node server.js" "start": "node server.js"
}, },
"dependencies": { "dependencies": {
"express": "^4.16.1" "express": "^4.16.1",
"prom-client" : "11.5.3"
} }
} }

View File

@ -7,10 +7,46 @@ const PORT = 5000;
const HOST = '0.0.0.0'; const HOST = '0.0.0.0';
// App // App
const client = require('prom-client');
const collectDefaultMetrics = client.collectDefaultMetrics;
// Probe every 5th second.
collectDefaultMetrics({ timeout: 5000 });
const counter = new client.Counter({
name: 'node_request_operations_total',
help: 'The total number of processed requests'
});
const histogram = new client.Histogram({
name: 'node_request_duration_seconds',
help: 'Histogram for the duration in seconds.',
buckets: [1, 2, 5, 6, 10]
});
const app = express(); const app = express();
app.get('/', (req, res) => { app.get('/', (req, res) => {
//Simulate a sleep
var start = new Date()
var simulateTime = 1000
setTimeout(function(argument) {
// execution time simulated with setTimeout function
var end = new Date() - start
histogram.observe(end / 1000); //convert to seconds
}, simulateTime)
counter.inc();
res.send('Hello world\n'); res.send('Hello world\n');
}); });
// Metrics endpoint
app.get('/metrics', (req, res) => {
res.set('Content-Type', client.register.contentType)
res.end(client.register.metrics())
})
app.listen(PORT, HOST); app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`); console.log(`Running on http://${HOST}:${PORT}`);

View File

@ -5,4 +5,4 @@ scrape_configs:
- job_name: my-application - job_name: my-application
honor_labels: true honor_labels: true
static_configs: static_configs:
- targets: ['go-application','python-application','dotnet-application','nodejs-application'] - targets: ['go-application:5000','python-application:5000','dotnet-application:5000','nodejs-application:5000']

View File

@ -1,21 +1,12 @@
FROM python:3.7.3-alpine3.9 as dev
RUN mkdir /work/
WORKDIR /work/
COPY ./src/requirements.txt /work/requirements.txt
RUN pip install -r requirements.txt
COPY ./src/ /work/
###########START NEW IMAGE###################
FROM python:3.7.3-alpine3.9 as prod FROM python:3.7.3-alpine3.9 as prod
RUN mkdir /app/ RUN mkdir /app/
WORKDIR /app/ WORKDIR /app/
COPY --from=dev /work/ /app/ COPY ./src/requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt RUN pip install -r requirements.txt
COPY ./src/ /app/
ENV FLASK_APP=server.py ENV FLASK_APP=server.py
CMD flask run -h 0.0.0 -p 5000 CMD flask run -h 0.0.0 -p 5000

View File

@ -1 +1,2 @@
Flask == 1.0.3 Flask == 1.0.3
prometheus_client == 0.7.1

View File

@ -1,6 +1,31 @@
from flask import Flask from flask import Response, Flask, request
import prometheus_client
from prometheus_client.core import CollectorRegistry
from prometheus_client import Summary, Counter, Histogram, Gauge
import time
app = Flask(__name__) app = Flask(__name__)
_INF = float("inf")
graphs = {}
graphs['c'] = Counter('python_request_operations_total', 'The total number of processed requests')
graphs['h'] = Histogram('python_request_duration_seconds', 'Histogram for the duration in seconds.', buckets=(1, 2, 5, 6, 10, _INF))
@app.route("/") @app.route("/")
def hello(): def hello():
return "Hello World!" start = time.time()
graphs['c'].inc()
time.sleep(0.600)
end = time.time()
graphs['h'].observe(end - start)
return "Hello World!"
@app.route("/metrics")
def requests_count():
res = []
for k,v in graphs.items():
res.append(prometheus_client.generate_latest(v))
return Response(res, mimetype="text/plain")

View File

@ -1,4 +1,55 @@
# Prometheus Application Monitoring # Prometheus Application Monitoring
## a Video reference guide ## a Video reference guide
coming soon! To run any of the commands, please ensure you open a terminal and navigate to the path where this readme is located.
## Start Prometheus
```
docker-compose up -d prometheus
docker-compose up -d grafana
```
Wait for Grafana to start up
Import the dashboards
```
TODO
```
You should see all application targets un `UNKNOWN` or `DOWN` status.
```http://localhost:9090/targets```
## Start the example app you prefer
```
docker-compose up -d golang-application
docker-compose up -d python-application
docker-compose up -d dotnet-application
docker-compose up -d nodejs-application
```
## Generate some requests by opening the application in the browser
```
http://localhost:80 #Golang
http://localhost:81 #Python
http://localhost:82 #Dotnet
http://localhost:83 #NodeJS
```
## Check Dashboards
```
http://localhost:3000
```
## Prometheus Queries
### Golang Examples
Requests per Second over 2minutes
```
irate(go_request_operations_total[2m])
```
Request duration
```
rate(go_request_duration_seconds_sum[2m]) / rate(go_request_duration_seconds_total[2m])
```