public void CommentLine() { var actual = Prometheus.Comment("A comment"); var expected = "# A comment"; Assert.Equal(expected, actual); }
public void ParseLine_For_Blank() { var input = " "; var result = Prometheus.ParseLine(input); Assert.True(result.IsBlank); }
public void MetricSimpleLine() { var actual = Prometheus.Metric("metric_without_timestamp_and_labels", 12.47); var expected = "metric_without_timestamp_and_labels 12.47"; Assert.Equal(expected, actual); }
public void HelpLine() { var actual = Prometheus.Help("http_requests_total", "The total number of HTTP requests."); var expected = "# HELP http_requests_total The total number of HTTP requests."; Assert.Equal(expected, actual); }
public void ParseLine_For_Comment() { var input = "# A comment"; var result = Prometheus.ParseLine(input); Assert.True(result.IsComment); var comment = result as Comment; Assert.Equal("A comment", comment.Text); }
public void MetricLine() { var labels = new Dictionary <string, string> { { "method", "post" }, { "code", "200" } }; var actual = Prometheus.Metric("http_requests_total", 1027, labels, DateTimeOffset.FromUnixTimeMilliseconds(1395066363000)); var expected = "http_requests_total{method=\"post\",code=\"200\"} 1027 1395066363000"; Assert.Equal(expected, actual); }
public void ParseLine_For_Type() { var input = " # TYPE http_requests_total counter"; var result = Prometheus.ParseLine(input); Assert.True(result.IsMetricType); var metricType = result as MetricType; Assert.Equal("http_requests_total", metricType.MetricName); Assert.Equal(MetricTypeEnum.Counter, metricType.MetricType); }
public void ParseLine_For_Help() { var input = " # HELP http_requests_total The total number of HTTP requests."; var result = Prometheus.ParseLine(input); Assert.True(result.IsHelp); var help = result as Help; Assert.Equal("http_requests_total", help.MetricName); Assert.Equal("The total number of HTTP requests.", help.Text); }
public static IMetricServer EnableMetricsServer(Prometheus config) { IMetricServer metricsServer = null; if (config.Enabled) { var port = config.Port ?? 4000; metricsServer = new KestrelMetricServer(port: port); metricsServer.Start(); Log.Information("Metrics Server started and listening on: http://localhost:{0}/metrics", port); } return(metricsServer); }
public void ParseLine_For_Metric() { var input = "http_requests_total{method=\"post\",code=\"200\"} 1027 1395066363000"; var result = Prometheus.ParseLine(input); Assert.True(result.IsMetric); var metric = result as Metric; Assert.Equal("http_requests_total", metric.MetricName); Assert.NotNull(metric.MetricValue); Assert.Equal(1027.0, metric.MetricValue.Value); Assert.Contains("method", metric.Labels); Assert.Contains("code", metric.Labels); Assert.Equal(DateTimeOffset.FromUnixTimeMilliseconds(1395066363000), metric.Timestamp); }
public static IDisposable EnableCollector(Prometheus config) { if (config.Enabled) { return(DotNetRuntimeStatsBuilder .Customize() .WithContentionStats() .WithJitStats() .WithThreadPoolStats() .WithGcStats() .WithExceptionStats() //.WithDebuggingMetrics(true) .WithErrorHandler(ex => Log.Error(ex, "Unexpected exception occurred in prometheus-net.DotNetRuntime")) .StartCollecting()); } return(null); }
public void ParseText() { var input = @"# HELP http_requests_total The total number of HTTP requests. # TYPE http_requests_total counter http_requests_total{method=""post"",code=""200""} 1027 1395066363000 http_requests_total{method=""post"",code=""400""} 3 1395066363000 # Escaping in label values: msdos_file_access_time_seconds{path=""C:\\DIR\\FILE.TXT"",error=""Cannot find file:\n \""FILE.TXT\"" ""} 1.458255915e9 # Minimalistic line: metric_without_timestamp_and_labels 12.47 # A weird metric from before the epoch: something_weird{problem=""division by zero""} +Inf -3982045"; var result = Prometheus.ParseText(input).ToArray(); Assert.Equal(13, result.Count()); Assert.True(result[0].IsHelp); }
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } var supportedCultures = new[] { new CultureInfo("en-US") }; app.UseRequestLocalization(new RequestLocalizationOptions { DefaultRequestCulture = new RequestCulture("en-US"), SupportedCultures = supportedCultures, SupportedUICultures = supportedCultures }); app.Run(async(context) => { string result = string.Empty; #region hyperv_cpu_total_run_time string counterHypervCpuTotalRunTimeName = "hyperv_cpu_total_run_time"; PerformanceCounter counterHypervCpuTotalRunTime = new PerformanceCounter("Hyper-V Hypervisor Logical Processor", "% Total Run Time", "_Total"); counterHypervCpuTotalRunTime.NextValue(); System.Threading.Thread.Sleep(1000); result += Prometheus.CreateMetricDescription( counterHypervCpuTotalRunTimeName, "gauge", "Virtual processor usage percentage in guest and hypervisor code." ); result += Prometheus.CreateMetric( counterHypervCpuTotalRunTimeName, counterHypervCpuTotalRunTime.NextValue().ToString(), string.Empty ); #endregion #region hyperv_memory_total_bytes string counterComputerInfoTotalPhysicalMemoryName = "hyperv_memory_total_bytes"; ComputerInfo computerInfo = new ComputerInfo(); result += Prometheus.CreateMetricDescription( counterComputerInfoTotalPhysicalMemoryName, "gauge", "Total physical memory." ); result += Prometheus.CreateMetric( counterComputerInfoTotalPhysicalMemoryName, computerInfo.TotalPhysicalMemory.ToString(), string.Empty ); #endregion #region hyperv_memory_avaliable_bytes string counterMemoryAvaliableBytesName = "hyperv_memory_avaliable_bytes"; PerformanceCounter counterMemoryAvaliableBytes = new PerformanceCounter("Memory", "Available Bytes"); counterMemoryAvaliableBytes.NextValue(); System.Threading.Thread.Sleep(1000); result += Prometheus.CreateMetricDescription( counterMemoryAvaliableBytesName, "gauge", "Total memory avaliable in bytes." ); result += Prometheus.CreateMetric( counterMemoryAvaliableBytesName, counterMemoryAvaliableBytes.NextValue().ToString(), string.Empty ); #endregion #region hyperv_network_adapter_bytes_total_sec string counterNetworkAdapterBytesTotalSecName = "hyperv_network_adapter_bytes_total_sec"; PerformanceCounterCategory categoryNetworkAdapterBytesTotalSec = PerformanceCounterCategory.GetCategories().FirstOrDefault(a => a.CategoryName == "Network Adapter"); string[] instanceNetworkAdapterBytesTotalSecNames = categoryNetworkAdapterBytesTotalSec.GetInstanceNames(); NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); result += Prometheus.CreateMetricDescription( counterNetworkAdapterBytesTotalSecName, "gauge", "Network adapter traffic (bytes total/sec)." ); foreach (string instanceName in instanceNetworkAdapterBytesTotalSecNames) { try { PerformanceCounter counterNetworkAdapterBytesTotalSec = new PerformanceCounter("Network Adapter", "Bytes Total/sec", instanceName); if (counterNetworkAdapterBytesTotalSec.RawValue > 0) { string name = networkInterfaces.AsEnumerable().Where(a => GenerateSlug(a.Description) == GenerateSlug(instanceName)).FirstOrDefault().Name; counterNetworkAdapterBytesTotalSec.NextValue(); System.Threading.Thread.Sleep(1000); result += Prometheus.CreateMetric( counterNetworkAdapterBytesTotalSecName, counterNetworkAdapterBytesTotalSec.NextValue().ToString(), "{adapter=\"" + GenerateSlug(name) + "\"}" ); } } catch (System.Exception ex) { Console.WriteLine("EXCEPTION: {0}", ex.Message); // throw; } } #endregion #region hyperv_logical_disk_total_megabytes and hyperv_logical_disk_avaliable_megabytes string counterDriveInfoTotalSizeName = "hyperv_logical_disk_total_megabytes"; DriveInfo[] allDrives = DriveInfo.GetDrives(); result += Prometheus.CreateMetricDescription( counterDriveInfoTotalSizeName, "gauge", "Total disk space." ); foreach (DriveInfo d in allDrives) { if (d.IsReady == true) { result += Prometheus.CreateMetric( counterDriveInfoTotalSizeName, (d.TotalSize / 1024 / 1024).ToString(), "{disk=\"" + GenerateSlug(d.Name) + "\"}" ); } } string counterLogicalDiskFreeMegabytesName = "hyperv_logical_disk_avaliable_megabytes"; result += Prometheus.CreateMetricDescription( counterLogicalDiskFreeMegabytesName, "gauge", "Logical disk free space (in MB)." ); foreach (DriveInfo d in allDrives) { if (d.IsReady == true) { result += Prometheus.CreateMetric( counterLogicalDiskFreeMegabytesName, (d.AvailableFreeSpace / 1024 / 1024).ToString(), "{disk=\"" + GenerateSlug(d.Name) + "\"}" ); } } #endregion await context.Response.WriteAsync(result); }); }
/// <summary> /// The AutoDevOps resource constructor, which takes care of deploying the whole thing /// </summary> /// <param name="settings">AutoDevOps settings, <see cref="AutoDevOpsSettings"/></param> /// <param name="sidecars">Optional: collection of sidecar containers</param> /// <param name="configureContainer">Optional: custom application container configuration</param> /// <param name="configurePod">Optional: custom pod configuration</param> /// <param name="configureDeployment">Optional: custom deployment configuration</param> /// <param name="configureService">Optional: custom service configuration</param> /// <param name="serviceAnnotations">Optional: service annotations</param> /// <param name="ingressAnnotations">Optional: ingress annotations</param> /// <param name="namespaceAnnotations">Optional: namespace annotations</param> /// <param name="deployExtras">Optional: use this to deploy other resources to the environment namespace, /// before the application is deployed.</param> /// <param name="provider">Optional: custom Kubernetes resource provider</param> public AutoDevOps( AutoDevOpsSettings settings, IEnumerable <ContainerArgs>?sidecars = null, Action <ContainerArgs>?configureContainer = null, Action <PodSpecArgs>?configurePod = null, Action <DeploymentArgs>?configureDeployment = null, Action <ServiceArgs>?configureService = null, Dictionary <string, string>?serviceAnnotations = null, Dictionary <string, string>?ingressAnnotations = null, Dictionary <string, string>?namespaceAnnotations = null, Action <Namespace>?deployExtras = null, ProviderResource?provider = null ) { var @namespace = KubeNamespace.Create(settings.Deploy.Namespace, namespaceAnnotations, provider); var namespaceName = @namespace.Metadata.Apply(x => x.Name); deployExtras?.Invoke(@namespace); var imagePullSecret = settings.GitLab.Visibility != "public" && settings.Registry != null ? KubeSecret.CreateRegistrySecret(namespaceName, settings.Registry, provider) : null; var replicas = settings.Deploy.Percentage > 0 || settings.Deploy.Replicas == 0 ? GetReplicas(settings.Application.Track, settings.Deploy.Percentage) : settings.Deploy.Replicas; if (replicas == 0) { DeploymentResult = new Result { Namespace = @namespace }; return; } var appSecret = KubeSecret.CreateAppSecret(namespaceName, settings, provider); var deployment = KubeDeployment.Create( namespaceName, settings, replicas, imagePullSecret, appSecret, sidecars, configureContainer, configurePod, configureDeployment, provider ); var service = settings.Service.Enabled ? KubeService.Create( namespaceName, settings, deployment, serviceAnnotations, configureService, provider ) : null; var ingress = settings.Ingress.Enabled && !settings.Deploy.Url.IsEmpty() ? KubeIngress.Create(namespaceName, settings, settings.Ingress.Class, ingressAnnotations, provider) : null; if (settings.Prometheus.Metrics && settings.Prometheus.Operator) { if (service != null) { Prometheus.CreateServiceMonitor(settings, service, @namespace, provider); } else { Prometheus.CreatePodMonitor(settings, deployment, @namespace, provider); } } DeploymentResult = new Result { Namespace = @namespace, Deployment = deployment, Service = service, Ingress = ingress }; }
public void Validate() { // Wire up the node label parents. foreach (var node in NodeDefinitions.Values) { if (node.Labels != null) { node.Labels.Node = node; } } // Validate the properties. Provisioner = Provisioner ?? defaultProvisioner; Kubernetes = Kubernetes ?? new KubernetesOptions(); Docker = Docker ?? new DockerOptions(); Ceph = Ceph ?? new CephOptions() { Enabled = false }; Mon = Mon ?? new MonOptions() { Enabled = false }; Prometheus = Prometheus ?? new PrometheusOptions() { Enabled = false }; DrivePrefix = DrivePrefix ?? defaultDrivePrefix; Setup = Setup ?? new SetupOptions(); Hosting = Hosting ?? new HostingOptions(); NodeOptions = NodeOptions ?? new NodeOptions(); Network = Network ?? new NetworkOptions(); Kubernetes.Validate(this); Docker.Validate(this); Ceph.Validate(this); Mon.Validate(this); Prometheus.Validate(this); Setup.Validate(this); Network.Validate(this); Hosting.Validate(this); NodeOptions.Validate(this); Network.Validate(this); new HostingManagerFactory().Validate(this); if (TimeSources == null || TimeSources.Length == 0 || TimeSources.Count(ts => string.IsNullOrWhiteSpace(ts)) > 0) { TimeSources = new string[] { "pool.ntp.org" }; } if (NodeDefinitions == null || NodeDefinitions.Count == 0) { throw new ClusterDefinitionException("At least one cluster node must be defined."); } foreach (var node in NodeDefinitions.Values) { node.Validate(this); } if (Name == null) { throw new ClusterDefinitionException($"The [{nameof(ClusterDefinition)}.{nameof(Name)}] property is required."); } if (!IsValidName(Name)) { throw new ClusterDefinitionException($"The [{nameof(ClusterDefinition)}.{nameof(Name)}={Name}] property is not valid. Only letters, numbers, periods, dashes, and underscores are allowed."); } if (Datacenter == null) { throw new ClusterDefinitionException($"The [{nameof(ClusterDefinition)}.{nameof(Datacenter)}] property is required."); } if (!IsValidName(Datacenter)) { throw new ClusterDefinitionException($"The [{nameof(ClusterDefinition)}.{nameof(Datacenter)}={Datacenter}] property is not valid. Only letters, numbers, periods, dashes, and underscores are allowed."); } var masterNodeCount = Masters.Count(); if (masterNodeCount == 0) { throw new ClusterDefinitionException("Clusters must have at least one master node."); } else if (masterNodeCount > 5) { throw new ClusterDefinitionException("Clusters may not have more than [5] master nodes."); } else if (!NeonHelper.IsOdd(masterNodeCount)) { throw new ClusterDefinitionException($"[{masterNodeCount}] master nodes is not allowed. Only an off number of master nodes is allowed: [1, 3, or 5]"); } if (!string.IsNullOrEmpty(PackageProxy)) { // Ensure that this is set to zero or more network endpoints // formatted like: // // HOSTNAME:PORT // ADDRESS:PORT foreach (var endpoint in PackageProxy.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)) { var fields = endpoint.Split(':'); if (!IPAddress.TryParse(fields[0], out var address) && !NetHelper.IsValidHost(fields[0])) { throw new ClusterDefinitionException($"Invalid IP address or HOSTNAME [{fields[0]}] in [{nameof(ClusterDefinition)}.{nameof(PackageProxy)}={PackageProxy}]."); } if (!int.TryParse(fields[1], out var port) || !NetHelper.IsValidPort(port)) { throw new ClusterDefinitionException($"Invalid port [{fields[1]}] in [{nameof(ClusterDefinition)}.{nameof(PackageProxy)}={PackageProxy}]."); } } } // Ensure that each node has a valid unique or NULL IP address. NetworkCidr nodesSubnet = null; if (Network.NodeSubnet != null) { nodesSubnet = NetworkCidr.Parse(Network.NodeSubnet); } var addressToNode = new Dictionary <string, NodeDefinition>(); foreach (var node in SortedNodes) { if (node.PrivateAddress != null) { NodeDefinition conflictNode; if (addressToNode.TryGetValue(node.PrivateAddress, out conflictNode)) { throw new ClusterDefinitionException($"Node [name={node.Name}] has invalid private IP address [{node.PrivateAddress}] that conflicts with node [name={conflictNode.Name}]."); } } } foreach (var node in SortedNodes) { if (node.PrivateAddress != null) { if (!IPAddress.TryParse(node.PrivateAddress, out var address)) { throw new ClusterDefinitionException($"Node [name={node.Name}] has invalid private IP address [{node.PrivateAddress}]."); } if (nodesSubnet != null && !nodesSubnet.Contains(address)) { throw new ClusterDefinitionException($"Node [name={node.Name}] has private IP address [{node.PrivateAddress}] that is not within the hosting [{nameof(Network.NodeSubnet)}={Network.NodeSubnet}]."); } } else if (!Hosting.IsCloudProvider) { throw new ClusterDefinitionException($"Node [name={node.Name}] is not assigned a private IP address. This is required when deploying to a [{nameof(Environment)}={Environment}] hosting environment."); } } }