├── prometheus-net-logo.png
├── src
├── Prometheus.SystemMetrics.Example.AOT
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Prometheus.SystemMetrics.Example.AOT.csproj
│ └── Dockerfile
├── Prometheus.SystemMetrics.Example
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── Program.cs
│ ├── Prometheus.SystemMetrics.Example.csproj
│ ├── Properties
│ │ └── launchSettings.json
│ └── Dockerfile
├── Prometheus.SystemMetrics
│ ├── Collectors
│ │ ├── DiskCollectorConfig.cs
│ │ ├── Obsolete
│ │ │ ├── MemoryCollector.cs
│ │ │ └── CpuUsageCollector.cs
│ │ ├── ISystemMetricCollector.cs
│ │ ├── MetricCollectorFacade.cs
│ │ ├── NetworkCollector.cs
│ │ ├── LinuxMemoryCollector.cs
│ │ ├── LoadAverageCollector.cs
│ │ ├── LinuxCpuUsageCollector.cs
│ │ ├── DiskCollector.cs
│ │ ├── WindowsCpuUsageCollector.cs
│ │ └── WindowsMemoryCollector.cs
│ ├── Native
│ │ ├── LinuxNative.cs
│ │ └── WindowsNative.cs
│ ├── Parsers
│ │ ├── MemInfoParser.cs
│ │ └── ProcStatParser.cs
│ ├── ServiceCollectionExtensions.cs
│ ├── SystemMetricsHostedService.cs
│ └── Prometheus.SystemMetrics.csproj
└── Prometheus.SystemMetrics.Tests
│ ├── Parsers
│ ├── MemInfoParserTest.cs
│ └── ProcStatParserTest.cs
│ └── Prometheus.SystemMetrics.Tests.csproj
├── .editorconfig
├── .dockerignore
├── .github
└── workflows
│ └── build.yml
├── LICENSE
├── prometheus-net.SystemMetrics.sln
├── README.md
└── .gitignore
/prometheus-net-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Daniel15/prometheus-net.SystemMetrics/HEAD/prometheus-net-logo.png
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example.AOT/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example.AOT/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # To learn more about .editorconfig see https://aka.ms/editorconfigdocs
2 | ###############################
3 | # Core EditorConfig Options #
4 | ###############################
5 | root = true
6 | # All files
7 | [*]
8 | indent_style = tab
9 |
10 | # Code files
11 | [*.{cs,csx,vb,vbx}]
12 | indent_size = 4
13 | insert_final_newline = true
14 | charset = utf-8-bom
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.classpath
2 | **/.dockerignore
3 | **/.env
4 | **/.git
5 | **/.gitignore
6 | **/.project
7 | **/.settings
8 | **/.toolstarget
9 | **/.vs
10 | **/.vscode
11 | **/*.*proj.user
12 | **/*.dbmdl
13 | **/*.jfm
14 | **/azds.yaml
15 | **/bin
16 | **/charts
17 | **/docker-compose*
18 | **/Dockerfile*
19 | **/node_modules
20 | **/npm-debug.log
21 | **/obj
22 | **/secrets.dev.yaml
23 | **/values.dev.yaml
24 | LICENSE
25 | README.md
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example.AOT/Program.cs:
--------------------------------------------------------------------------------
1 | using Prometheus;
2 | using Prometheus.SystemMetrics;
3 |
4 | var builder = WebApplication.CreateSlimBuilder(args);
5 |
6 | var services = builder.Services;
7 | services.AddSystemMetrics();
8 |
9 | var app = builder.Build();
10 |
11 | if (app.Environment.IsDevelopment())
12 | {
13 | app.UseDeveloperExceptionPage();
14 | }
15 |
16 | app.UseRouting();
17 | app.MapMetrics();
18 | app.MapGet("/", async context =>
19 | {
20 | context.Response.Redirect("/metrics");
21 | });
22 |
23 | app.Run();
24 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/DiskCollectorConfig.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 |
4 | namespace Prometheus.SystemMetrics.Collectors
5 | {
6 | ///
7 | /// Configuration for
8 | ///
9 | public class DiskCollectorConfig
10 | {
11 | ///
12 | /// Drive types to collect data on. By default, only collects data for "fixed" drives.
13 | ///
14 | public HashSet DriveTypes { get; set; } = new HashSet { DriveType.Fixed };
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Setup .NET Core
17 | uses: actions/setup-dotnet@v1
18 | with:
19 | dotnet-version: 8.0.x
20 | - name: Install dependencies
21 | run: dotnet restore
22 | - name: Build
23 | run: dotnet build --configuration Release --no-restore
24 | - name: Test
25 | run: dotnet test --no-restore --verbosity normal
26 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.Extensions.Hosting;
3 | using Prometheus;
4 | using Prometheus.SystemMetrics;
5 |
6 | var builder = WebApplication.CreateSlimBuilder(args);
7 |
8 | var services = builder.Services;
9 | services.AddSystemMetrics();
10 |
11 | var app = builder.Build();
12 |
13 | if (app.Environment.IsDevelopment())
14 | {
15 | app.UseDeveloperExceptionPage();
16 | }
17 |
18 | app.UseRouting();
19 | app.MapMetrics();
20 | app.MapGet("/", async context =>
21 | {
22 | context.Response.Redirect("/metrics");
23 | });
24 |
25 | app.Run();
26 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/Obsolete/MemoryCollector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Prometheus.SystemMetrics.Collectors
4 | {
5 | ///
6 | /// Collects data on overall CPU usage
7 | ///
8 | [Obsolete("Use LinuxMemoryCollector or WindowsMemoryCollector")]
9 | public class MemoryCollector : MetricCollectorFacade
10 | {
11 | ///
12 | /// All the collectors to try. The first one that returns true for
13 | /// IsSupported will be used.
14 | ///
15 | protected override ISystemMetricCollector[] Collectors => new ISystemMetricCollector[]
16 | {
17 | new LinuxMemoryCollector(),
18 | new WindowsMemoryCollector(),
19 | };
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/Obsolete/CpuUsageCollector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Prometheus.SystemMetrics.Collectors
4 | {
5 | ///
6 | /// Collects data on overall CPU usage
7 | ///
8 | [Obsolete("Use LinuxCpuUsageCollector or WindowsCpuUsageCollector")]
9 | public class CpuUsageCollector : MetricCollectorFacade
10 | {
11 | ///
12 | /// All the collectors to try. The first one that returns true for
13 | /// IsSupported will be used.
14 | ///
15 | protected override ISystemMetricCollector[] Collectors => new ISystemMetricCollector[]
16 | {
17 | #if !NETFRAMEWORK
18 | new LinuxCpuUsageCollector(),
19 | #endif
20 | new WindowsCpuUsageCollector(),
21 | };
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example.AOT/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "http": {
4 | "commandName": "Project",
5 | "launchBrowser": true,
6 | "launchUrl": "todos",
7 | "environmentVariables": {
8 | "ASPNETCORE_ENVIRONMENT": "Development"
9 | },
10 | "dotnetRunMessages": true,
11 | "applicationUrl": "http://localhost:5017"
12 | },
13 | "Docker": {
14 | "commandName": "Docker",
15 | "launchBrowser": true,
16 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/todos",
17 | "environmentVariables": {
18 | "ASPNETCORE_HTTP_PORTS": "8080"
19 | },
20 | "publishAllPorts": true
21 | }
22 | },
23 | "$schema": "http://json.schemastore.org/launchsettings.json"
24 | }
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example/Prometheus.SystemMetrics.Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | 7de7626a-382c-4e69-82cb-b140615e853e
6 | Linux
7 | ..\..
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/ISystemMetricCollector.cs:
--------------------------------------------------------------------------------
1 | namespace Prometheus.SystemMetrics.Collectors
2 | {
3 | ///
4 | /// Represents a mechanism for collecting some sort of metrics.
5 | ///
6 | public interface ISystemMetricCollector
7 | {
8 | ///
9 | /// Gets whether this metric is supported on the current system.
10 | ///
11 | bool IsSupported { get; }
12 |
13 | ///
14 | /// Creates the Prometheus metric.
15 | ///
16 | /// Factory to create metric using
17 | void CreateMetrics(MetricFactory factory);
18 |
19 | ///
20 | /// Update data for the metrics. Called immediately before the metrics are scraped.
21 | ///
22 | void UpdateMetrics();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example.AOT/Prometheus.SystemMetrics.Example.AOT.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 | true
8 | true
9 | Linux
10 | ..\..
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:13431",
7 | "sslPort": 44372
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "Prometheus.SystemMetrics.Example": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "environmentVariables": {
22 | "ASPNETCORE_ENVIRONMENT": "Development"
23 | },
24 | "applicationUrl": "http://localhost:5000"
25 | },
26 | "Docker": {
27 | "commandName": "Docker",
28 | "launchBrowser": true,
29 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
30 | "publishAllPorts": true,
31 | "useSSL": true
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example/Dockerfile:
--------------------------------------------------------------------------------
1 | #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
2 |
3 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
4 | USER app
5 | WORKDIR /app
6 | EXPOSE 80
7 | EXPOSE 443
8 |
9 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
10 | ARG BUILD_CONFIGURATION=Release
11 | WORKDIR /src
12 | COPY ["src/Prometheus.SystemMetrics.Example/Prometheus.SystemMetrics.Example.csproj", "src/Prometheus.SystemMetrics.Example/"]
13 | RUN dotnet restore "src/Prometheus.SystemMetrics.Example/Prometheus.SystemMetrics.Example.csproj"
14 | COPY . .
15 | WORKDIR "/src/."
16 | RUN dotnet build "Prometheus.SystemMetrics.Example.csproj" -c $BUILD_CONFIGURATION -o /app/build
17 |
18 | FROM build AS publish
19 | ARG BUILD_CONFIGURATION=Release
20 | RUN dotnet publish "./WebApplication4.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
21 |
22 | FROM base AS final
23 | WORKDIR /app
24 | COPY --from=publish /app/publish .
25 | ENTRYPOINT ["dotnet", "Prometheus.SystemMetrics.Example.dll"]
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2020 Daniel Lo Nigro (Daniel15)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Native/LinuxNative.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Prometheus.SystemMetrics.Native
4 | {
5 | ///
6 | /// Native API calls for Linux.
7 | ///
8 | internal static partial class LinuxNative
9 | {
10 | public const int SC_CLK_TCK = 0x2;
11 |
12 | #if NET7_0_OR_GREATER
13 | [LibraryImport("libc", SetLastError = true)]
14 | [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
15 | internal static partial int getloadavg(double[] loadavg, int nelem);
16 |
17 | [LibraryImport("libc", SetLastError = true)]
18 | [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
19 | internal static partial long sysconf(int name);
20 | #else
21 | [DllImport("libc", SetLastError = true)]
22 | [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
23 | internal static extern int getloadavg(double[] loadavg, int nelem);
24 |
25 | [DllImport("libc", SetLastError = true)]
26 | [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
27 | internal static extern long sysconf(int name);
28 | #endif
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Tests/Parsers/MemInfoParserTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Prometheus.SystemMetrics.Parsers;
3 | using Xunit;
4 |
5 | namespace Prometheus.SystemMetrics.Tests.Parsers
6 | {
7 | public class MemInfoTest
8 | {
9 | private const int BYTES_IN_KB = 1024;
10 |
11 | [Fact]
12 | public void ParsesMemInfo()
13 | {
14 | const string input = @"
15 | MemTotal: 16470140 kB
16 | MemFree: 3690788 kB
17 | Buffers: 34032 kB
18 | Cached: 188576 kB
19 | Active(anon): 103104 kB
20 | Inactive(anon): 17440 kB
21 | Active(file): 64452 kB
22 | Dirty: 0 kB
23 | HugePages_Total: 0
24 | ";
25 | var result = MemInfoParser.Parse(input);
26 | result.Should().BeEquivalentTo(new[]
27 | {
28 | ("MemTotal", 16470140L * BYTES_IN_KB),
29 | ("MemFree", 3690788L * BYTES_IN_KB),
30 | ("Buffers", 34032L * BYTES_IN_KB),
31 | ("Cached", 188576L * BYTES_IN_KB),
32 | ("Active(anon)", 103104L * BYTES_IN_KB),
33 | ("Inactive(anon)", 17440L * BYTES_IN_KB),
34 | ("Active(file)", 64452L * BYTES_IN_KB),
35 | ("Dirty", 0),
36 | });
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Tests/Prometheus.SystemMetrics.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | all
15 | runtime; build; native; contentfiles; analyzers; buildtransitive
16 |
17 |
18 | all
19 | runtime; build; native; contentfiles; analyzers; buildtransitive
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Example.AOT/Dockerfile:
--------------------------------------------------------------------------------
1 | #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
2 |
3 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
4 | USER app
5 | WORKDIR /app
6 | EXPOSE 8080
7 |
8 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
9 | # Install clang/zlib1g-dev dependencies for publishing to native
10 | RUN apt-get update \
11 | && apt-get install -y --no-install-recommends \
12 | clang zlib1g-dev
13 | ARG BUILD_CONFIGURATION=Release
14 | WORKDIR /src
15 | COPY ["src/Prometheus.SystemMetrics.Example.AOT/Prometheus.SystemMetrics.Example.AOT.csproj", "src/Prometheus.SystemMetrics.Example.AOT/"]
16 | RUN dotnet restore "./src/Prometheus.SystemMetrics.Example.AOT/./Prometheus.SystemMetrics.Example.AOT.csproj"
17 | COPY . .
18 | WORKDIR "/src/src/Prometheus.SystemMetrics.Example.AOT"
19 | RUN dotnet build "./Prometheus.SystemMetrics.Example.AOT.csproj" -c $BUILD_CONFIGURATION -o /app/build
20 |
21 | FROM build AS publish
22 | ARG BUILD_CONFIGURATION=Release
23 | RUN dotnet publish "./Prometheus.SystemMetrics.Example.AOT.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=true
24 |
25 | FROM mcr.microsoft.com/dotnet/runtime-deps:8.0 AS final
26 | WORKDIR /app
27 | EXPOSE 8080
28 | COPY --from=publish /app/publish .
29 | ENTRYPOINT ["./Prometheus.SystemMetrics.Example.AOT"]
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/MetricCollectorFacade.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 |
3 | namespace Prometheus.SystemMetrics.Collectors
4 | {
5 | ///
6 | /// Wraps multiple metric collectors and uses the first one that is supported by the system.
7 | ///
8 | public abstract class MetricCollectorFacade : ISystemMetricCollector
9 | {
10 | private ISystemMetricCollector? _innerCollector = null;
11 |
12 | ///
13 | /// Creates a new
14 | ///
15 | public MetricCollectorFacade()
16 | {
17 | _innerCollector = Collectors.FirstOrDefault(x => x.IsSupported);
18 | }
19 |
20 | ///
21 | /// Gets whether this metric is supported on the current system.
22 | ///
23 | public bool IsSupported => _innerCollector != null;
24 |
25 | ///
26 | /// Creates the Prometheus metric.
27 | ///
28 | /// Factory to create metric using
29 | public void CreateMetrics(MetricFactory factory)
30 | {
31 | _innerCollector?.CreateMetrics(factory);
32 | }
33 |
34 | ///
35 | /// Update data for the metrics. Called immediately before the metrics are scraped.
36 | ///
37 | public void UpdateMetrics()
38 | {
39 | _innerCollector?.UpdateMetrics();
40 | }
41 |
42 | ///
43 | /// All the collectors to try. The first one that returns true for
44 | /// will be used.
45 | ///
46 | protected abstract ISystemMetricCollector[] Collectors { get; }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Parsers/MemInfoParser.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Text.RegularExpressions;
5 |
6 | namespace Prometheus.SystemMetrics.Parsers
7 | {
8 | ///
9 | /// Parser for /proc/meminfo files
10 | ///
11 | public static class MemInfoParser
12 | {
13 | ///
14 | /// Location of the meminfo file
15 | ///
16 | public const string MEMINFO_FILE = "/proc/meminfo";
17 |
18 | private const int BYTES_IN_KB = 1024;
19 |
20 | ///
21 | /// eg. "MemTotal: 12345 kB"
22 | ///
23 | private static readonly Regex _lineRegex = new Regex(
24 | @"^(?[^:]+):\s+(?\d+) kB",
25 | RegexOptions.Multiline | RegexOptions.Compiled
26 | );
27 |
28 | ///
29 | /// Parses the /proc/meminfo file.
30 | ///
31 | ///
32 | public static IEnumerable<(string field, ulong value)> Parse()
33 | {
34 | return Parse(File.ReadAllText(MEMINFO_FILE));
35 | }
36 |
37 | ///
38 | /// Parses the specified contents of the meminfo file.
39 | ///
40 | /// Content to parse
41 | /// Parsed rows
42 | public static IEnumerable<(string field, ulong value)> Parse(string file)
43 | {
44 | return _lineRegex.Matches(file)
45 | .Cast()
46 | .Select(
47 | match => (
48 | match.Groups["name"].Value.TrimStart(),
49 | ulong.Parse(match.Groups["value"].Value) * BYTES_IN_KB
50 | )
51 | );
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/NetworkCollector.cs:
--------------------------------------------------------------------------------
1 | using System.Net.NetworkInformation;
2 |
3 | namespace Prometheus.SystemMetrics.Collectors
4 | {
5 | ///
6 | /// Collects data on network usage
7 | ///
8 | public class NetworkCollector : ISystemMetricCollector
9 | {
10 | internal Counter NetworkReceived { get; private set; } = default!;
11 | internal Counter NetworkSent { get; private set; } = default!;
12 |
13 | ///
14 | /// Gets whether this metric is supported on the current system.
15 | ///
16 | public bool IsSupported => true;
17 |
18 | ///
19 | /// Creates the Prometheus metric.
20 | ///
21 | /// Factory to create metric using
22 | public void CreateMetrics(MetricFactory factory)
23 | {
24 | NetworkReceived = factory.CreateCounter(
25 | "node_network_receive_bytes_total",
26 | "Bytes received over the network",
27 | "device"
28 | );
29 | NetworkSent = factory.CreateCounter(
30 | "node_network_transmit_bytes_total",
31 | "Bytes sent over the network",
32 | "device"
33 | );
34 | }
35 |
36 | ///
37 | /// Update data for the metrics. Called immediately before the metrics are scraped.
38 | ///
39 | public void UpdateMetrics()
40 | {
41 | foreach (var iface in NetworkInterface.GetAllNetworkInterfaces())
42 | {
43 | var stats = iface.GetIPStatistics();
44 | NetworkReceived.WithLabels(iface.Name).IncTo(stats.BytesReceived);
45 | NetworkSent.WithLabels(iface.Name).IncTo(stats.BytesSent);
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/LinuxMemoryCollector.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using Prometheus.SystemMetrics.Parsers;
4 |
5 | namespace Prometheus.SystemMetrics.Collectors
6 | {
7 | ///
8 | /// Collects memory usage information, on Linux.
9 | ///
10 | public class LinuxMemoryCollector : ISystemMetricCollector
11 | {
12 | ///
13 | /// Gets whether this metric is supported on the current system.
14 | ///
15 | public bool IsSupported => File.Exists(MemInfoParser.MEMINFO_FILE);
16 |
17 | ///
18 | /// Metrics for memory collection.
19 | ///
20 | internal IReadOnlyDictionary _metrics = new Dictionary();
21 |
22 | ///
23 | /// Creates the Prometheus metric.
24 | ///
25 | /// Factory to create metric using
26 | public void CreateMetrics(MetricFactory factory)
27 | {
28 | var metrics = new Dictionary();
29 | foreach (var (name, _) in MemInfoParser.Parse())
30 | {
31 | var cleanName = name.Replace('(', '_').Replace(")", "");
32 | cleanName = $"node_memory_{cleanName}_bytes";
33 | metrics[name] = factory.CreateGauge(cleanName, $"Memory information field {name}");
34 | }
35 | _metrics = metrics;
36 | }
37 |
38 | ///
39 | /// Update data for the metrics. Called immediately before the metrics are scraped.
40 | ///
41 | public void UpdateMetrics()
42 | {
43 | foreach (var (name, value) in MemInfoParser.Parse())
44 | {
45 | if (_metrics.TryGetValue(name, out var gauge))
46 | {
47 | gauge.Set(value);
48 | }
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/LoadAverageCollector.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using Prometheus.SystemMetrics.Native;
3 |
4 | namespace Prometheus.SystemMetrics.Collectors
5 | {
6 | ///
7 | /// Collects data on system load average
8 | ///
9 | public class LoadAverageCollector : ISystemMetricCollector
10 | {
11 | internal Gauge Load1 { get; private set; } = default!;
12 | internal Gauge Load5 { get; private set; } = default!;
13 | internal Gauge Load15 { get; private set; } = default!;
14 |
15 | ///
16 | /// Gets whether this metric is supported on the current system.
17 | ///
18 | #if NETFRAMEWORK
19 | public bool IsSupported => false;
20 | #else
21 | public bool IsSupported => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
22 | #endif
23 |
24 | ///
25 | /// Creates the Prometheus metric.
26 | ///
27 | /// Factory to create metric using
28 | public void CreateMetrics(MetricFactory factory)
29 | {
30 | Load1 = factory.CreateGauge("node_load1", "Load average over the last minute.");
31 | Load5 = factory.CreateGauge("node_load5", "Load average over the last 5 minutes.");
32 | Load15 = factory.CreateGauge("node_load15", "Load average over the last 15 minutes.");
33 | }
34 |
35 | ///
36 | /// Update data for the metrics. Called immediately before the metrics are scraped.
37 | ///
38 | public void UpdateMetrics()
39 | {
40 | var loadAverage = new double[3];
41 | if (LinuxNative.getloadavg(loadAverage, 3) == 3)
42 | {
43 | Load1.Set(loadAverage[0]);
44 | Load5.Set(loadAverage[1]);
45 | Load15.Set(loadAverage[2]);
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/ServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Prometheus.SystemMetrics.Collectors;
4 |
5 | namespace Prometheus.SystemMetrics
6 | {
7 | ///
8 | /// Adds SystemMetrics classes to the .
9 | ///
10 | public static class ServiceCollectionExtensions
11 | {
12 | ///
13 | /// Adds the SystemMetrics classes to the .
14 | ///
15 | public static IServiceCollection AddSystemMetrics(this IServiceCollection services, bool registerDefaultCollectors = true)
16 | {
17 | services.AddHostedService();
18 | services.AddOptions();
19 |
20 | if (registerDefaultCollectors)
21 | {
22 | services.AddSystemMetricCollector();
23 | services.AddSystemMetricCollector();
24 | services.AddSystemMetricCollector();
25 |
26 | #if !NETFRAMEWORK
27 | services.AddSystemMetricCollector();
28 | #endif
29 | services.AddSystemMetricCollector();
30 |
31 | services.AddSystemMetricCollector();
32 | services.AddSystemMetricCollector();
33 | }
34 |
35 | return services;
36 | }
37 |
38 | ///
39 | /// Adds a system metric collector to the
40 | ///
41 | /// Metric to add
42 | #if NET7_0_OR_GREATER
43 | public static IServiceCollection AddSystemMetricCollector<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(this IServiceCollection services)
44 | #else
45 | public static IServiceCollection AddSystemMetricCollector(this IServiceCollection services)
46 | #endif
47 | where T : class, ISystemMetricCollector
48 | {
49 | services.AddSingleton();
50 | return services;
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/LinuxCpuUsageCollector.cs:
--------------------------------------------------------------------------------
1 | #if !NETFRAMEWORK
2 | using System.IO;
3 | using Prometheus.SystemMetrics.Native;
4 | using Prometheus.SystemMetrics.Parsers;
5 |
6 | namespace Prometheus.SystemMetrics.Collectors
7 | {
8 | ///
9 | /// Collects data on overall CPU usage, on Linux
10 | ///
11 | public class LinuxCpuUsageCollector : ISystemMetricCollector
12 | {
13 | ///
14 | /// File to read stats from
15 | ///
16 | private const string STAT_FILE = "/proc/stat";
17 |
18 | internal Counter Cpu { get; private set; } = default!;
19 |
20 | private int _clockTicksPerSecond = 100;
21 |
22 | ///
23 | /// Gets whether this metric is supported on the current system.
24 | ///
25 | public bool IsSupported => File.Exists(STAT_FILE);
26 |
27 | ///
28 | /// Creates the Prometheus metric.
29 | ///
30 | /// Factory to create metric using
31 | public void CreateMetrics(MetricFactory factory)
32 | {
33 | Cpu = factory.CreateCounter(
34 | "node_cpu_seconds_total",
35 | "Seconds the CPU spent in each mode",
36 | "cpu",
37 | "mode"
38 | );
39 |
40 | _clockTicksPerSecond = (int)LinuxNative.sysconf(LinuxNative.SC_CLK_TCK);
41 | }
42 |
43 | ///
44 | /// Update data for the metrics. Called immediately before the metrics are scraped.
45 | ///
46 | public void UpdateMetrics()
47 | {
48 | var usage = ProcStatParser.ParseCpuUsage(File.ReadAllText(STAT_FILE), _clockTicksPerSecond);
49 | foreach (var data in usage)
50 | {
51 | var cpuIndex = data.CpuIndex.ToString();
52 | Cpu.WithLabels(cpuIndex, "idle").IncTo(data.Idle);
53 | Cpu.WithLabels(cpuIndex, "iowait").IncTo(data.IoWait);
54 | Cpu.WithLabels(cpuIndex, "irq").IncTo(data.Irq);
55 | Cpu.WithLabels(cpuIndex, "nice").IncTo(data.Nice);
56 | Cpu.WithLabels(cpuIndex, "softirq").IncTo(data.SoftIrq);
57 | Cpu.WithLabels(cpuIndex, "steal").IncTo(data.Steal);
58 | Cpu.WithLabels(cpuIndex, "system").IncTo(data.System);
59 | Cpu.WithLabels(cpuIndex, "user").IncTo(data.User);
60 | }
61 | }
62 | }
63 | }
64 | #endif
65 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/SystemMetricsHostedService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using Microsoft.Extensions.Hosting;
7 | using Microsoft.Extensions.Logging;
8 | using Prometheus.SystemMetrics.Collectors;
9 |
10 | namespace Prometheus.SystemMetrics
11 | {
12 | ///
13 | /// Handles registering SystemMetrics with Prometheus on app startup.
14 | ///
15 | public class SystemMetricsHostedService : IHostedService
16 | {
17 | private readonly IEnumerable _collectors;
18 | private readonly ILogger _logger;
19 |
20 | ///
21 | /// Creates a new
22 | ///
23 | public SystemMetricsHostedService(
24 | IEnumerable collectors,
25 | ILogger logger
26 | )
27 | {
28 | _collectors = collectors;
29 | _logger = logger;
30 | }
31 | ///
32 | /// Triggered when the application host is ready to start the service.
33 | ///
34 | /// Indicates that the start process has been aborted.
35 | public Task StartAsync(CancellationToken cancellationToken)
36 | {
37 | // TODO: Should allow injecting a custom registry
38 | var registry = Metrics.DefaultRegistry;
39 | var factory = Metrics.WithCustomRegistry(registry);
40 | foreach (var collector in _collectors.Where(collector => collector.IsSupported))
41 | {
42 | try
43 | {
44 | collector.CreateMetrics(factory);
45 | registry.AddBeforeCollectCallback(collector.UpdateMetrics);
46 | }
47 | catch (Exception ex)
48 | {
49 | _logger.LogError(ex, $"Could not initialize {collector.GetType().Name}. Some metrics will be missing.");
50 | }
51 | }
52 |
53 | return Task.CompletedTask;
54 | }
55 |
56 | ///
57 | /// Triggered when the application host is performing a graceful shutdown.
58 | ///
59 | /// Indicates that the shutdown process should no longer be graceful.
60 | public Task StopAsync(CancellationToken cancellationToken)
61 | {
62 | return Task.CompletedTask;
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Prometheus.SystemMetrics.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net462;netstandard2.0;net8.0
5 | enable
6 | latestMajor
7 | true
8 |
9 | true
10 | prometheus-net.SystemMetrics
11 | prometheus-net.SystemMetrics
12 | Daniel Lo Nigro
13 | Export system metrics (CPU usage, disk usage, etc) to Prometheus from your .NET app.
14 | MIT
15 | https://github.com/Daniel15/prometheus-net.SystemMetrics
16 | https://github.com/Daniel15/prometheus-net.SystemMetrics
17 | true
18 | true
19 | true
20 | true
21 | snupkg
22 | prometheus-net-logo.png
23 | prometheus prometheus-net systemmetrics cpu system metrics disk network
24 | 3.0.0
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | True
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/DiskCollector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using Microsoft.Extensions.Logging;
6 | using Microsoft.Extensions.Options;
7 |
8 | namespace Prometheus.SystemMetrics.Collectors
9 | {
10 | ///
11 | /// Collects data on disk usage.
12 | ///
13 | public class DiskCollector : ISystemMetricCollector
14 | {
15 | private readonly ILogger _logger;
16 | private readonly HashSet _driveTypes;
17 |
18 | internal Gauge DiskSpace { get; private set; } = default!;
19 | internal Gauge Size { get; private set; } = default!;
20 |
21 | ///
22 | /// Creates a new .
23 | ///
24 | public DiskCollector(IOptions config, ILogger logger)
25 | {
26 | _logger = logger;
27 | _driveTypes = config.Value.DriveTypes;
28 | }
29 |
30 | ///
31 | /// Gets whether this metric is supported on the current system.
32 | ///
33 | public bool IsSupported => true;
34 |
35 | ///
36 | /// Creates the Prometheus metric.
37 | ///
38 | /// Factory to create metric using
39 | public void CreateMetrics(MetricFactory factory)
40 | {
41 | DiskSpace = factory.CreateGauge(
42 | "node_filesystem_avail_bytes",
43 | "Free disk space",
44 | "mountpoint",
45 | "fstype"
46 | );
47 |
48 | Size = factory.CreateGauge(
49 | "node_filesystem_size_bytes",
50 | "Filesystem size in bytes",
51 | "mountpoint",
52 | "fstype"
53 | );
54 | }
55 |
56 | ///
57 | /// Update data for the metrics. Called immediately before the metrics are scraped.
58 | ///
59 | public void UpdateMetrics()
60 | {
61 | foreach (var drive in DriveInfo.GetDrives().Where(x => _driveTypes.Contains(x.DriveType)))
62 | {
63 | try
64 | {
65 | DiskSpace.WithLabels(drive.Name, drive.DriveFormat).Set(drive.AvailableFreeSpace);
66 | Size.WithLabels(drive.Name, drive.DriveFormat).Set(drive.TotalSize);
67 | }
68 | catch (Exception ex)
69 | {
70 | _logger.LogWarning("Could not get information for disk {0}: {1}", drive.Name, ex.Message);
71 | }
72 | }
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/prometheus-net.SystemMetrics.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.8.34309.116
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Prometheus.SystemMetrics", "src\Prometheus.SystemMetrics\Prometheus.SystemMetrics.csproj", "{C65859B3-4125-4594-A6BF-8917C1549E16}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Prometheus.SystemMetrics.Example", "src\Prometheus.SystemMetrics.Example\Prometheus.SystemMetrics.Example.csproj", "{C965DA91-6C2A-4D62-B32C-DA42CA5A6146}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Prometheus.SystemMetrics.Tests", "src\Prometheus.SystemMetrics.Tests\Prometheus.SystemMetrics.Tests.csproj", "{D76966FB-8E1F-40F7-B47B-D2AC03927906}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Prometheus.SystemMetrics.Example.AOT", "src\Prometheus.SystemMetrics.Example.AOT\Prometheus.SystemMetrics.Example.AOT.csproj", "{FF2F4C3A-A4CF-4ACB-8828-60967517E163}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {C65859B3-4125-4594-A6BF-8917C1549E16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {C65859B3-4125-4594-A6BF-8917C1549E16}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {C65859B3-4125-4594-A6BF-8917C1549E16}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {C65859B3-4125-4594-A6BF-8917C1549E16}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {C965DA91-6C2A-4D62-B32C-DA42CA5A6146}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {C965DA91-6C2A-4D62-B32C-DA42CA5A6146}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {C965DA91-6C2A-4D62-B32C-DA42CA5A6146}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {C965DA91-6C2A-4D62-B32C-DA42CA5A6146}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {D76966FB-8E1F-40F7-B47B-D2AC03927906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {D76966FB-8E1F-40F7-B47B-D2AC03927906}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {D76966FB-8E1F-40F7-B47B-D2AC03927906}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {D76966FB-8E1F-40F7-B47B-D2AC03927906}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {FF2F4C3A-A4CF-4ACB-8828-60967517E163}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {FF2F4C3A-A4CF-4ACB-8828-60967517E163}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {FF2F4C3A-A4CF-4ACB-8828-60967517E163}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {FF2F4C3A-A4CF-4ACB-8828-60967517E163}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {0340F015-CD49-4C6E-8C95-1C2AC3E8229D}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Parsers/ProcStatParser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace Prometheus.SystemMetrics.Parsers
6 | {
7 | ///
8 | /// Handles parsing Linux /proc/stat file.
9 | ///
10 | ///
11 | /// Docs: http://man7.org/linux/man-pages/man5/proc.5.html
12 | ///
13 | public static class ProcStatParser
14 | {
15 | ///
16 | /// Parses CPU usage data from /proc/stat
17 | ///
18 | /// Raw data
19 | /// Number of clock ticks per second (from _SC_CLK_TCK)
20 | /// Nicely-formatted CPU usage data
21 | public static IEnumerable ParseCpuUsage(string stats, int clockTicksPerSecond)
22 | {
23 | return stats
24 | .Split(new[] { "\r\n", "\n" }, StringSplitOptions.None)
25 | .Where(x => x.StartsWith("cpu") && !x.StartsWith("cpu "))
26 | .Select(line => new CpuUsageData(line, clockTicksPerSecond));
27 | }
28 |
29 | ///
30 | /// Represents CPU usage data from /proc/stat
31 | ///
32 | ///
33 | /// Docs: http://man7.org/linux/man-pages/man5/proc.5.html
34 | ///
35 | public readonly struct CpuUsageData
36 | {
37 | ///
38 | /// Parses a line from /proc/stat
39 | ///
40 | public CpuUsageData(string rawLine, int clockTicksPerSecond)
41 | {
42 | double ParseCpuStat(string rawValue)
43 | {
44 | return double.Parse(rawValue) / clockTicksPerSecond;
45 | }
46 |
47 | var pieces = rawLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
48 | CpuIndex = ushort.Parse(pieces[0].Replace("cpu", string.Empty));
49 | User = ParseCpuStat(pieces[1]);
50 | Nice = ParseCpuStat(pieces[2]);
51 | System = ParseCpuStat(pieces[3]);
52 | Idle = ParseCpuStat(pieces[4]);
53 | IoWait = ParseCpuStat(pieces[5]);
54 | Irq = ParseCpuStat(pieces[6]);
55 | SoftIrq = ParseCpuStat(pieces[7]);
56 | Steal = ParseCpuStat(pieces[8]);
57 | }
58 |
59 | ///
60 | /// The index of the CPU. Starts at 0 for the first CPU.
61 | ///
62 | public ushort CpuIndex { get; }
63 |
64 | ///
65 | /// Time spent in the idle task. This value should be USER_HZ times the second entry in the /proc/uptime pseudo-file.
66 | ///
67 | public double Idle { get; }
68 |
69 | ///
70 | /// Time waiting for I/O to complete.
71 | ///
72 | public double IoWait { get; }
73 |
74 | ///
75 | /// Time servicing interrupts.
76 | ///
77 | public double Irq { get; }
78 | ///
79 | /// Time spent in user mode with low priority (nice).
80 | ///
81 | public double Nice { get; }
82 |
83 | ///
84 | /// Time servicing softirqs.
85 | ///
86 | public double SoftIrq { get; }
87 |
88 | ///
89 | /// Time spent in system mode.
90 | ///
91 | public double System { get; }
92 |
93 | ///
94 | /// Stolen time, which is the time spent in other operating systems when running in a virtualized environment
95 | ///
96 | public double Steal { get; }
97 |
98 | ///
99 | /// Time spent in user mode.
100 | ///
101 | public double User { get; }
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/WindowsCpuUsageCollector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Runtime.InteropServices;
5 |
6 | namespace Prometheus.SystemMetrics.Collectors
7 | {
8 | ///
9 | /// Collects data on overall CPU usage, on Windows
10 | ///
11 | public class WindowsCpuUsageCollector : ISystemMetricCollector
12 | {
13 | internal Counter Cpu { get; private set; } = default!;
14 |
15 | // {counter name => {cpu index => counter}
16 | private IDictionary _counters =
17 | new Dictionary();
18 |
19 | ///
20 | /// Gets whether this metric is supported on the current system.
21 | ///
22 | #if NETFRAMEWORK
23 | public bool IsSupported => true;
24 | #else
25 | public bool IsSupported => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
26 | #endif
27 |
28 | private static readonly Dictionary _labels = new()
29 | {
30 | { "% Privileged Time", "system" },
31 | { "% Interrupt Time", "irq" },
32 | { "% Idle Time", "idle" },
33 | { "% User Time", "user" }
34 | };
35 |
36 | private const int NS_IN_SEC = 1000000000;
37 | private const int COUNTER_100NS_IN_SEC = NS_IN_SEC / 100;
38 | ///
39 | /// Once a counter reaches this threshold, it's recreated.
40 | /// https://github.com/Daniel15/prometheus-net.SystemMetrics/issues/9
41 | ///
42 | private const float RECREATE_COUNTER_THRESHOLD = 4000000;
43 |
44 | ///
45 | /// Creates the Prometheus metric.
46 | ///
47 | /// Factory to create metric using
48 | public void CreateMetrics(MetricFactory factory)
49 | {
50 | if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
51 | {
52 | return;
53 | }
54 |
55 | // Create one counter per metric per CPU
56 | foreach (var kvp in _labels)
57 | {
58 | _counters[kvp.Key] = new PerformanceCounter[Environment.ProcessorCount];
59 | for (var i = 0; i < Environment.ProcessorCount; i++)
60 | {
61 | CreateCounter(kvp.Key, i);
62 | }
63 | }
64 |
65 | Cpu = factory.CreateCounter(
66 | "node_cpu_seconds_total",
67 | "Seconds the CPU spent in each mode",
68 | "cpu",
69 | "mode"
70 | );
71 | }
72 |
73 | private void CreateCounter(string counterName, int cpuIndex)
74 | {
75 | var oldCounter = _counters[counterName][cpuIndex];
76 | oldCounter?.Dispose();
77 |
78 | var newCounter = new PerformanceCounter("Processor", counterName, cpuIndex.ToString());
79 | if (newCounter.CounterType != PerformanceCounterType.Timer100Ns)
80 | {
81 | throw new Exception(
82 | "A CPU counter was not of type Timer100Ns. Please report a bug to the prometheus-net.SystemMetrics project"
83 | );
84 | }
85 | _counters[counterName][cpuIndex] = newCounter;
86 | }
87 |
88 | ///
89 | /// Update data for the metrics. Called immediately before the metrics are scraped.
90 | ///
91 | public void UpdateMetrics()
92 | {
93 | if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
94 | {
95 | return;
96 | }
97 |
98 | foreach (var kvp in _counters)
99 | {
100 | var cpuIndex = 0;
101 | foreach (var performanceCounter in kvp.Value)
102 | {
103 | // Assumes all counters are Timer100Ns type
104 | var value = (double)performanceCounter.RawValue / COUNTER_100NS_IN_SEC;
105 | Cpu.WithLabels(
106 | performanceCounter.InstanceName,
107 | _labels[performanceCounter.CounterName]
108 | ).IncTo(value);
109 |
110 | // If this counter is getting large, recreate it. Prometheus correctly handles
111 | // counters rolling over, so this shouldn't cause any issues.
112 | // https://github.com/Daniel15/prometheus-net.SystemMetrics/issues/9
113 | if (value >= RECREATE_COUNTER_THRESHOLD)
114 | {
115 | CreateCounter(kvp.Key, cpuIndex);
116 | }
117 | cpuIndex++;
118 | }
119 | }
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # prometheus-net SystemMetrics
2 |
3 | [](https://www.nuget.org/packages/prometheus-net.SystemMetrics/)
4 | 
5 |
6 | prometheus-net SystemMetrics allows you to export various system metrics (such as CPU usage, disk usage, etc) from your .NET application to Prometheus. It is designed to be a very lightweight alternative to `node_exporter`, only containing essential metrics. This is useful on systems with limited RAM or where it is easier to add this library to your app instead of deploying a totally separate service.
7 |
8 | # Usage
9 |
10 | Install the `prometheus-net.SystemMetrics` library using NuGet.
11 |
12 | Add the services to your `Startup.cs`:
13 |
14 | ```csharp
15 | using Prometheus.SystemMetrics;
16 |
17 | public void ConfigureServices(IServiceCollection services)
18 | {
19 | // ...
20 | services.AddSystemMetrics();
21 | }
22 | ```
23 |
24 | If you have not already done so, you will also need to expose the Prometheus metrics endpoint by calling `MapMetrics` in `Configure`:
25 |
26 | ```csharp
27 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
28 | {
29 | // ...
30 | app.UseRouting();
31 | app.UseEndpoints(endpoints =>
32 | {
33 | endpoints.MapMetrics();
34 | // ...
35 | });
36 | }
37 | ```
38 |
39 | After doing this, going to `/metrics` should return the new metrics.
40 |
41 | ## Customization
42 |
43 | By default, this will add all the collectors. To only add some collectors, you can instead only render the collectors you want to use:
44 |
45 | ```csharp
46 | services.AddSystemMetrics(registerDefaultCollectors: false);
47 | services.AddSystemMetricCollector();
48 | ```
49 |
50 | # Metrics
51 |
52 | Where possible, metrics have the same name and format as `node_exporter`.
53 |
54 | ## CPU
55 |
56 | The number of seconds the CPU has spent in each mode (system, user, idle, etc). Available on **Linux** and **Windows**. Example data:
57 |
58 | ```
59 | node_cpu_seconds_total{cpu="0",mode="system"} 172.35
60 | node_cpu_seconds_total{cpu="0",mode="user"} 292.27
61 | node_cpu_seconds_total{cpu="0",mode="idle"} 30760.4
62 | ```
63 |
64 | ## Disk
65 |
66 | The amount of free disk space on all mounts. Available on **all platforms**. Example data:
67 |
68 | ```
69 | # Linux
70 | node_filesystem_avail_bytes{mountpoint="/",fstype="ext4"} 57061916672
71 |
72 | # Windows
73 | node_filesystem_avail_bytes{mountpoint="C:\\",fstype="NTFS"} 101531594752
74 | ```
75 |
76 | ## Load Average
77 |
78 | Available on **Linux**. Example data:
79 |
80 | ```
81 | node_load1 0.06
82 | node_load5 0.03
83 | node_load15 0.26
84 | ```
85 |
86 | ## Memory
87 |
88 | Stats such as available RAM, RAM used by caches, etc. Available on **Linux** and **Windows**. Example data:
89 |
90 | ```
91 | node_memory_MemAvailable_bytes 1527701504
92 | node_memory_Cached_bytes 572964864
93 | node_memory_MemFree_bytes 961966080
94 | node_memory_MemTotal_bytes 2085904384
95 | ```
96 |
97 | ## Network
98 |
99 | Total amount of data sent and received over the network. Available on **all platforms**. Example data:
100 |
101 | ```
102 | node_network_transmit_bytes_total{device="eth0"} 3053723
103 | node_network_receive_bytes_total{device="eth0"} 5822231
104 | ```
105 |
106 | # Changelog
107 |
108 | ## 3.0.0 - 30th November 2023
109 |
110 | * Bumped to .NET 8.0.
111 | * Bumped prometheus-net dependency to version 8.
112 | * Wrapped metric collector creation in try-catch so that one collector failing doesn't break the whole app.
113 | * Updated Windows memory counters so their names more closely match the Linux version. Notably, `node_memory_MemFree` is now `node_memory_MemAvailable_bytes`, and `node_memory_MemTotal` is now `node_memory_MemTotal_bytes`. Currently, both the old and new counters exist (for backwards compatibility), but the old ones will be removed in the next major version.
114 |
115 | ## 2.0.0 - 8th October 2021
116 |
117 | * Added memory and CPU collectors for Windows (thanks to @masterworgen for the initial implementation in PR #3).
118 | * Added .NET Framework 4.6.2 builds, since prometheus-net itself supports this framework version.
119 |
120 | ## 1.0.1 - 17th May 2020
121 |
122 | * Added memory stats for Linux.
123 | * Added total file size to disk collector.
124 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Native/WindowsNative.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Prometheus.SystemMetrics.Native
4 | {
5 | ///
6 | /// Native API calls for Windows.
7 | ///
8 | internal static partial class WindowsNative
9 | {
10 | #if NET7_0_OR_GREATER
11 | ///
12 | /// Retrieves information about the system's current usage of both physical and virtual memory.
13 | /// See https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex
14 | ///
15 | [return: MarshalAs(UnmanagedType.Bool)]
16 | [LibraryImport("kernel32.dll", SetLastError = true)]
17 | [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
18 | internal static partial bool GlobalMemoryStatusEx(ref MemoryStatusEx lpBuffer);
19 | #else
20 | ///
21 | /// Retrieves information about the system's current usage of both physical and virtual memory.
22 | /// See https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex
23 | ///
24 | [return: MarshalAs(UnmanagedType.Bool)]
25 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
26 | [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
27 | internal static extern bool GlobalMemoryStatusEx(ref MemoryStatusEx lpBuffer);
28 | #endif
29 | }
30 |
31 | ///
32 | /// Contains information about the current state of both physical and virtual memory, including extended memory.
33 | /// See https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex
34 | ///
35 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
36 | internal struct MemoryStatusEx
37 | {
38 | ///
39 | /// The size of the structure, in bytes. You must set this member before calling
40 | /// GlobalMemoryStatusEx.
41 | ///
42 | public uint dwLength;
43 |
44 | ///
45 | /// A number between 0 and 100 that specifies the approximate percentage of physical memory
46 | /// that is in use (0 indicates no memory use and 100 indicates full memory use).
47 | ///
48 | public uint dwMemoryLoad;
49 |
50 | ///
51 | /// The amount of actual physical memory, in bytes.
52 | ///
53 | public ulong ullTotalPhys;
54 |
55 | ///
56 | /// The amount of physical memory currently available, in bytes. This is the amount of physical
57 | /// memory that can be immediately reused without having to write its contents to disk first.
58 | /// It is the sum of the size of the standby, free, and zero lists.
59 | ///
60 | public ulong ullAvailPhys;
61 |
62 | ///
63 | /// The current committed memory limit for the system or the current process, whichever is
64 | /// smaller, in bytes. To get the system-wide committed memory limit, call GetPerformanceInfo.
65 | ///
66 | public ulong ullTotalPageFile;
67 |
68 | ///
69 | /// The maximum amount of memory the current process can commit, in bytes. This value is
70 | /// equal to or smaller than the system-wide available commit value. To calculate the
71 | /// system-wide available commit value, call GetPerformanceInfo and subtract the value
72 | /// of CommitTotal from the value of CommitLimit.
73 | ///
74 | public ulong ullAvailPageFile;
75 |
76 | ///
77 | /// The size of the user-mode portion of the virtual address space of the calling process,
78 | /// in bytes. This value depends on the type of process, the type of processor, and the
79 | /// configuration of the operating system. For example, this value is approximately 2 GB
80 | /// for most 32-bit processes on an x86 processor and approximately 3 GB for 32-bit
81 | /// processes that are large address aware running on a system with 4-gigabyte tuning
82 | /// enabled.
83 | ///
84 | public ulong ullTotalVirtual;
85 |
86 | ///
87 | /// The amount of unreserved and uncommitted memory currently in the user-mode portion
88 | /// of the virtual address space of the calling process, in bytes.
89 | ///
90 | public ulong ullAvailVirtual;
91 |
92 | ///
93 | /// Reserved. This value is always 0.
94 | ///
95 | public ulong ullAvailExtendedVirtual;
96 |
97 | ///
98 | /// Creates a new instance of .
99 | ///
100 | public MemoryStatusEx()
101 | {
102 | dwLength = (uint)Marshal.SizeOf();
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics.Tests/Parsers/ProcStatParserTest.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using FluentAssertions;
3 | using FluentAssertions.Execution;
4 | using Prometheus.SystemMetrics.Parsers;
5 | using Xunit;
6 |
7 | namespace Prometheus.SystemMetrics.Tests.Parsers
8 | {
9 | public class ProcStatParserTest
10 | {
11 | private const int CLOCK_TICKS_PER_SECOND = 100;
12 |
13 | [Fact]
14 | public void ParsesProcStatOneCpu()
15 | {
16 | const string input = @"
17 | cpu 25797356 475644 10905875 237407016 8561195 0 790919 1433602 0 0
18 | cpu0 25797356 475644 10905875 237407016 8561195 0 790919 1433602 0 0
19 | intr 2102264361 2 9 0 0 0 0 3 0 1 0 0 33 15 0 0 2863339 0 0 0 0 0 0 0 0 0 142080017 0 187462829 141643800 0 0 0 0 0 0 2766816 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
20 | ctxt 5373393714
21 | btime 1586466311
22 | processes 23736296
23 | procs_running 1
24 | procs_blocked 0
25 | softirq 1500396835 0 271650897 70556582 475462237 143674570 0 54787062 0 6656 484258831
26 | ";
27 |
28 | var result = ProcStatParser.ParseCpuUsage(input, CLOCK_TICKS_PER_SECOND).ToList();
29 |
30 | using (new AssertionScope())
31 | {
32 | result.Should().HaveCount(1);
33 | var data = result[0];
34 | data.CpuIndex.Should().Be(0);
35 | data.Idle.Should().Be(2374070.16);
36 | data.IoWait.Should().Be(85611.95);
37 | data.Irq.Should().Be(0);
38 | data.Nice.Should().Be(4756.44);
39 | data.SoftIrq.Should().Be(7909.19);
40 | data.Steal.Should().Be(14336.02);
41 | data.System.Should().Be(109058.75);
42 | data.User.Should().Be(257973.56);
43 | }
44 | }
45 |
46 | [Fact]
47 | public void ParsesProcStatMultipleCpus()
48 | {
49 | const string input = @"
50 | cpu 6856179 266112 3643053 367130039 407323 0 97515 6363431 0 0
51 | cpu0 2713121 59602 1047164 90730609 93013 0 27443 1370766 0 0
52 | cpu1 1387186 67885 921779 91950147 114170 0 42502 1801892 0 0
53 | cpu2 1414461 71115 943043 92038864 110648 0 18255 1736643 0 0
54 | cpu3 1341410 67508 731065 92410418 89490 0 9313 1454128 0 0
55 | intr 304984032 3 9 0 0 0 0 0 0 0 0 0 0 3 0 0 942829 0 0 0 0 0 0 0 0 0 1636816 0 13318452 7577792 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
56 | ctxt 599038287
57 | btime 1588487095
58 | processes 636829
59 | procs_running 3
60 | procs_blocked 0
61 | softirq 214206550 0 68470359 13 31547001 2150475 0 1007474 41089356 794 69941078
62 | ";
63 |
64 | var result = ProcStatParser.ParseCpuUsage(input, CLOCK_TICKS_PER_SECOND).ToList();
65 |
66 | result.Should().HaveCount(4);
67 |
68 | using (new AssertionScope())
69 | {
70 | result[0].CpuIndex.Should().Be(0);
71 | result[0].Idle.Should().Be(907306.09);
72 | result[0].IoWait.Should().Be(930.13);
73 | result[0].Irq.Should().Be(0);
74 | result[0].Nice.Should().Be(596.02);
75 | result[0].SoftIrq.Should().Be(274.43);
76 | result[0].Steal.Should().Be(13707.66);
77 | result[0].System.Should().Be(10471.64);
78 | result[0].User.Should().Be(27131.21);
79 | }
80 |
81 | using (new AssertionScope())
82 | {
83 | result[1].CpuIndex.Should().Be(1);
84 | result[1].Idle.Should().Be(919501.47);
85 | result[1].IoWait.Should().Be(1141.7);
86 | result[1].Irq.Should().Be(0);
87 | result[1].Nice.Should().Be(678.85);
88 | result[1].SoftIrq.Should().Be(425.02);
89 | result[1].Steal.Should().Be(18018.92);
90 | result[1].System.Should().Be(9217.79);
91 | result[1].User.Should().Be(13871.86);
92 | }
93 |
94 | using (new AssertionScope())
95 | {
96 | result[2].CpuIndex.Should().Be(2);
97 | result[2].Idle.Should().Be(920388.64);
98 | result[2].IoWait.Should().Be(1106.48);
99 | result[2].Irq.Should().Be(0);
100 | result[2].Nice.Should().Be(711.15);
101 | result[2].SoftIrq.Should().Be(182.55);
102 | result[2].Steal.Should().Be(17366.43);
103 | result[2].System.Should().Be(9430.43);
104 | result[2].User.Should().Be(14144.61);
105 | }
106 |
107 | using (new AssertionScope())
108 | {
109 | result[3].CpuIndex.Should().Be(3);
110 | result[3].Idle.Should().Be(924104.18);
111 | result[3].IoWait.Should().Be(894.9);
112 | result[3].Irq.Should().Be(0);
113 | result[3].Nice.Should().Be(675.08);
114 | result[3].SoftIrq.Should().Be(93.13);
115 | result[3].Steal.Should().Be(14541.28);
116 | result[3].System.Should().Be(7310.65);
117 | result[3].User.Should().Be(13414.1);
118 | }
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/Prometheus.SystemMetrics/Collectors/WindowsMemoryCollector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using Prometheus.SystemMetrics.Native;
4 |
5 | namespace Prometheus.SystemMetrics.Collectors
6 | {
7 | ///
8 | /// Collects memory usage information, on Windows.
9 | ///
10 | public class WindowsMemoryCollector : ISystemMetricCollector
11 | {
12 | ///
13 | /// Gets whether this metric is supported on the current system.
14 | ///
15 | #if NETFRAMEWORK
16 | public bool IsSupported => true;
17 | #else
18 | public bool IsSupported => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
19 | #endif
20 |
21 | internal Gauge MemoryLoad { get; private set; } = default!;
22 | internal Gauge PageFileAvailable { get; private set; } = default!;
23 | internal Gauge PageFileTotal { get; private set; } = default!;
24 | internal Gauge PhysicalAvailable { get; private set; } = default!;
25 | internal Gauge PhysicalTotal { get; private set; } = default!;
26 | internal Gauge VirtualAvailable { get; private set; } = default!;
27 | internal Gauge VirtualTotal { get; private set; } = default!;
28 |
29 | internal Gauge LegacyPageFileAvailable { get; private set; } = default!;
30 | internal Gauge LegacyPageFileTotal { get; private set; } = default!;
31 | internal Gauge LegacyPhysicalAvailable { get; private set; } = default!;
32 | internal Gauge LegacyPhysicalTotal { get; private set; } = default!;
33 | internal Gauge LegacyVirtualAvailable { get; private set; } = default!;
34 | internal Gauge LegacyVirtualTotal { get; private set; } = default!;
35 |
36 |
37 | ///
38 | /// Creates the Prometheus metric.
39 | ///
40 | /// Factory to create metric using
41 | public void CreateMetrics(MetricFactory factory)
42 | {
43 | MemoryLoad = Metrics.CreateGauge(
44 | "node_memory_MemoryLoad",
45 | "A number between 0 and 100 that specifies the approximate percentage of physical memory that is in use (0 indicates no memory use and 100 indicates full memory use)."
46 | );
47 |
48 | PageFileAvailable = Metrics.CreateGauge(
49 | "node_memory_PageFileFree_bytes",
50 | "The maximum amount of memory the current process can commit, in bytes."
51 | );
52 | PageFileTotal = Metrics.CreateGauge(
53 | "node_memory_PageFileTotal_bytes",
54 | "The current committed memory limit for the system or the current process, whichever is smaller, in bytes."
55 | );
56 |
57 | PhysicalAvailable = Metrics.CreateGauge(
58 | "node_memory_MemAvailable_bytes",
59 | "The amount of physical memory currently available, in bytes. This is the amount of physical memory that can be immediately reused without having to write its contents to disk first."
60 | );
61 | PhysicalTotal = Metrics.CreateGauge(
62 | "node_memory_MemTotal_bytes",
63 | "The amount of actual physical memory, in bytes."
64 | );
65 |
66 | VirtualAvailable = Metrics.CreateGauge(
67 | "node_memory_VirtualFree_bytes",
68 | "The amount of unreserved and uncommitted memory currently in the user-mode portion of the virtual address space of the calling process, in bytes."
69 | );
70 | VirtualTotal = Metrics.CreateGauge(
71 | "node_memory_VirtualTotal_bytes",
72 | " The size of the user-mode portion of the virtual address space of the calling process, in bytes. This value depends on the type of process, the type of processor, and the configuration of the operating system. For example, this value is approximately 2 GB for most 32-bit processes on an x86 processor and approximately 3 GB for 32-bit processes that are large address aware running on a system with 4-gigabyte tuning"
73 | );
74 |
75 | LegacyPageFileAvailable = Metrics.CreateGauge(
76 | "node_memory_PageFileFree",
77 | "DEPRECATED: Use node_memory_PageFileFree_bytes instead."
78 | );
79 | LegacyPageFileTotal = Metrics.CreateGauge(
80 | "node_memory_PageFileTotal",
81 | "DEPRECATED: Use node_memory_PageFileTotal_bytes instead."
82 | );
83 |
84 | LegacyPhysicalAvailable = Metrics.CreateGauge(
85 | "node_memory_MemFree",
86 | "DEPRECATED: Use node_memory_MemAvailable_bytes instead."
87 | );
88 | LegacyPhysicalTotal = Metrics.CreateGauge(
89 | "node_memory_MemTotal",
90 | "DEPRECATED: Use node_memory_MemTotal_bytes instead."
91 | );
92 |
93 | LegacyVirtualAvailable = Metrics.CreateGauge(
94 | "node_memory_VirtualFree",
95 | "DEPRECATED: Use node_memory_VirtualFree_bytes instead."
96 | );
97 | LegacyVirtualTotal = Metrics.CreateGauge(
98 | "node_memory_VirtualTotal",
99 | "DEPRECATED: Use node_memory_VirtualTotal_bytes instead"
100 | );
101 | }
102 |
103 | ///
104 | /// Update data for the metrics. Called immediately before the metrics are scraped.
105 | ///
106 | public void UpdateMetrics()
107 | {
108 | var memStatus = new MemoryStatusEx();
109 |
110 | if (!WindowsNative.GlobalMemoryStatusEx(ref memStatus))
111 | {
112 | throw new Exception(Marshal.GetLastWin32Error().ToString());
113 | }
114 |
115 | MemoryLoad.Set(memStatus.dwMemoryLoad);
116 | PageFileAvailable.Set(memStatus.ullAvailPageFile);
117 | PageFileTotal.Set(memStatus.ullTotalPageFile);
118 | PhysicalAvailable.Set(memStatus.ullAvailPhys);
119 | PhysicalTotal.Set(memStatus.ullTotalPhys);
120 | VirtualAvailable.Set(memStatus.ullAvailVirtual);
121 | VirtualTotal.Set(memStatus.ullTotalVirtual);
122 |
123 | LegacyPageFileAvailable.Set(memStatus.ullAvailPageFile);
124 | LegacyPageFileTotal.Set(memStatus.ullTotalPageFile);
125 | LegacyPhysicalAvailable.Set(memStatus.ullAvailPhys);
126 | LegacyPhysicalTotal.Set(memStatus.ullTotalPhys);
127 | LegacyVirtualAvailable.Set(memStatus.ullAvailVirtual);
128 | LegacyVirtualTotal.Set(memStatus.ullTotalVirtual);
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.vspscc
94 | *.vssscc
95 | .builds
96 | *.pidb
97 | *.svclog
98 | *.scc
99 |
100 | # Chutzpah Test files
101 | _Chutzpah*
102 |
103 | # Visual C++ cache files
104 | ipch/
105 | *.aps
106 | *.ncb
107 | *.opendb
108 | *.opensdf
109 | *.sdf
110 | *.cachefile
111 | *.VC.db
112 | *.VC.VC.opendb
113 |
114 | # Visual Studio profiler
115 | *.psess
116 | *.vsp
117 | *.vspx
118 | *.sap
119 |
120 | # Visual Studio Trace Files
121 | *.e2e
122 |
123 | # TFS 2012 Local Workspace
124 | $tf/
125 |
126 | # Guidance Automation Toolkit
127 | *.gpState
128 |
129 | # ReSharper is a .NET coding add-in
130 | _ReSharper*/
131 | *.[Rr]e[Ss]harper
132 | *.DotSettings.user
133 |
134 | # TeamCity is a build add-in
135 | _TeamCity*
136 |
137 | # DotCover is a Code Coverage Tool
138 | *.dotCover
139 |
140 | # AxoCover is a Code Coverage Tool
141 | .axoCover/*
142 | !.axoCover/settings.json
143 |
144 | # Coverlet is a free, cross platform Code Coverage Tool
145 | coverage*[.json, .xml, .info]
146 |
147 | # Visual Studio code coverage results
148 | *.coverage
149 | *.coveragexml
150 |
151 | # NCrunch
152 | _NCrunch_*
153 | .*crunch*.local.xml
154 | nCrunchTemp_*
155 |
156 | # MightyMoose
157 | *.mm.*
158 | AutoTest.Net/
159 |
160 | # Web workbench (sass)
161 | .sass-cache/
162 |
163 | # Installshield output folder
164 | [Ee]xpress/
165 |
166 | # DocProject is a documentation generator add-in
167 | DocProject/buildhelp/
168 | DocProject/Help/*.HxT
169 | DocProject/Help/*.HxC
170 | DocProject/Help/*.hhc
171 | DocProject/Help/*.hhk
172 | DocProject/Help/*.hhp
173 | DocProject/Help/Html2
174 | DocProject/Help/html
175 |
176 | # Click-Once directory
177 | publish/
178 |
179 | # Publish Web Output
180 | *.[Pp]ublish.xml
181 | *.azurePubxml
182 | # Note: Comment the next line if you want to checkin your web deploy settings,
183 | # but database connection strings (with potential passwords) will be unencrypted
184 | *.pubxml
185 | *.publishproj
186 |
187 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
188 | # checkin your Azure Web App publish settings, but sensitive information contained
189 | # in these scripts will be unencrypted
190 | PublishScripts/
191 |
192 | # NuGet Packages
193 | *.nupkg
194 | # NuGet Symbol Packages
195 | *.snupkg
196 | # The packages folder can be ignored because of Package Restore
197 | **/[Pp]ackages/*
198 | # except build/, which is used as an MSBuild target.
199 | !**/[Pp]ackages/build/
200 | # Uncomment if necessary however generally it will be regenerated when needed
201 | #!**/[Pp]ackages/repositories.config
202 | # NuGet v3's project.json files produces more ignorable files
203 | *.nuget.props
204 | *.nuget.targets
205 |
206 | # Microsoft Azure Build Output
207 | csx/
208 | *.build.csdef
209 |
210 | # Microsoft Azure Emulator
211 | ecf/
212 | rcf/
213 |
214 | # Windows Store app package directories and files
215 | AppPackages/
216 | BundleArtifacts/
217 | Package.StoreAssociation.xml
218 | _pkginfo.txt
219 | *.appx
220 | *.appxbundle
221 | *.appxupload
222 |
223 | # Visual Studio cache files
224 | # files ending in .cache can be ignored
225 | *.[Cc]ache
226 | # but keep track of directories ending in .cache
227 | !?*.[Cc]ache/
228 |
229 | # Others
230 | ClientBin/
231 | ~$*
232 | *~
233 | *.dbmdl
234 | *.dbproj.schemaview
235 | *.jfm
236 | *.pfx
237 | *.publishsettings
238 | orleans.codegen.cs
239 |
240 | # Including strong name files can present a security risk
241 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
242 | #*.snk
243 |
244 | # Since there are multiple workflows, uncomment next line to ignore bower_components
245 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
246 | #bower_components/
247 |
248 | # RIA/Silverlight projects
249 | Generated_Code/
250 |
251 | # Backup & report files from converting an old project file
252 | # to a newer Visual Studio version. Backup files are not needed,
253 | # because we have git ;-)
254 | _UpgradeReport_Files/
255 | Backup*/
256 | UpgradeLog*.XML
257 | UpgradeLog*.htm
258 | ServiceFabricBackup/
259 | *.rptproj.bak
260 |
261 | # SQL Server files
262 | *.mdf
263 | *.ldf
264 | *.ndf
265 |
266 | # Business Intelligence projects
267 | *.rdl.data
268 | *.bim.layout
269 | *.bim_*.settings
270 | *.rptproj.rsuser
271 | *- [Bb]ackup.rdl
272 | *- [Bb]ackup ([0-9]).rdl
273 | *- [Bb]ackup ([0-9][0-9]).rdl
274 |
275 | # Microsoft Fakes
276 | FakesAssemblies/
277 |
278 | # GhostDoc plugin setting file
279 | *.GhostDoc.xml
280 |
281 | # Node.js Tools for Visual Studio
282 | .ntvs_analysis.dat
283 | node_modules/
284 |
285 | # Visual Studio 6 build log
286 | *.plg
287 |
288 | # Visual Studio 6 workspace options file
289 | *.opt
290 |
291 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
292 | *.vbw
293 |
294 | # Visual Studio LightSwitch build output
295 | **/*.HTMLClient/GeneratedArtifacts
296 | **/*.DesktopClient/GeneratedArtifacts
297 | **/*.DesktopClient/ModelManifest.xml
298 | **/*.Server/GeneratedArtifacts
299 | **/*.Server/ModelManifest.xml
300 | _Pvt_Extensions
301 |
302 | # Paket dependency manager
303 | .paket/paket.exe
304 | paket-files/
305 |
306 | # FAKE - F# Make
307 | .fake/
308 |
309 | # CodeRush personal settings
310 | .cr/personal
311 |
312 | # Python Tools for Visual Studio (PTVS)
313 | __pycache__/
314 | *.pyc
315 |
316 | # Cake - Uncomment if you are using it
317 | # tools/**
318 | # !tools/packages.config
319 |
320 | # Tabs Studio
321 | *.tss
322 |
323 | # Telerik's JustMock configuration file
324 | *.jmconfig
325 |
326 | # BizTalk build output
327 | *.btp.cs
328 | *.btm.cs
329 | *.odx.cs
330 | *.xsd.cs
331 |
332 | # OpenCover UI analysis results
333 | OpenCover/
334 |
335 | # Azure Stream Analytics local run output
336 | ASALocalRun/
337 |
338 | # MSBuild Binary and Structured Log
339 | *.binlog
340 |
341 | # NVidia Nsight GPU debugger configuration file
342 | *.nvuser
343 |
344 | # MFractors (Xamarin productivity tool) working folder
345 | .mfractor/
346 |
347 | # Local History for Visual Studio
348 | .localhistory/
349 |
350 | # BeatPulse healthcheck temp database
351 | healthchecksdb
352 |
353 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
354 | MigrationBackup/
355 |
356 | # Ionide (cross platform F# VS Code tools) working folder
357 | .ionide/
358 |
359 | # Fody - auto-generated XML schema
360 | FodyWeavers.xsd
361 |
--------------------------------------------------------------------------------