├── 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 | [![NuGet version](http://img.shields.io/nuget/v/prometheus-net.SystemMetrics.svg)](https://www.nuget.org/packages/prometheus-net.SystemMetrics/)  4 | ![Build Status](https://img.shields.io/github/workflow/status/Daniel15/prometheus-net.SystemMetrics/Build) 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 | --------------------------------------------------------------------------------