Skip to content
This repository was archived by the owner on Dec 18, 2023. It is now read-only.

Commit 6fa9ba7

Browse files
Prometheus exporter (#39)
* skeleton of premetheus exporter * almost ready * added skeleton for prometheus exporter * escabing of labels
1 parent c93b396 commit 6fa9ba7

File tree

13 files changed

+784
-5
lines changed

13 files changed

+784
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Unreleased
22

3+
- Initial implementation of Prometheus exporter.
34
- Initial version of Application Insights exporter implemented.
45
- Zipkin exporter implemented.
56
- Initial version of SDK published. It is based on contribution from Pivotal

OpenCensus.sln

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ EndProject
3737
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenCensus.Exporter.ApplicationInsights", "src\OpenCensus.Exporter.ApplicationInsights\OpenCensus.Exporter.ApplicationInsights.csproj", "{4493F5D9-874E-4FBF-B2F3-37890BD910E0}"
3838
EndProject
3939
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples", "src\Samples\Samples.csproj", "{C58393EB-32E2-4AC6-9170-697B36306E15}"
40+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenCensus.Exporter.Prometheus", "src\OpenCensus.Exporter.Prometheus\OpenCensus.Exporter.Prometheus.csproj", "{A86AF35D-9E84-4B12-AA0E-1C558DC2EE1C}"
4041
EndProject
4142
Global
4243
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -64,6 +65,10 @@ Global
6465
{C58393EB-32E2-4AC6-9170-697B36306E15}.Debug|Any CPU.Build.0 = Debug|Any CPU
6566
{C58393EB-32E2-4AC6-9170-697B36306E15}.Release|Any CPU.ActiveCfg = Release|Any CPU
6667
{C58393EB-32E2-4AC6-9170-697B36306E15}.Release|Any CPU.Build.0 = Release|Any CPU
68+
{A86AF35D-9E84-4B12-AA0E-1C558DC2EE1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
69+
{A86AF35D-9E84-4B12-AA0E-1C558DC2EE1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
70+
{A86AF35D-9E84-4B12-AA0E-1C558DC2EE1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
71+
{A86AF35D-9E84-4B12-AA0E-1C558DC2EE1C}.Release|Any CPU.Build.0 = Release|Any CPU
6772
EndGlobalSection
6873
GlobalSection(SolutionProperties) = preSolution
6974
HideSolutionNode = FALSE

README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,35 @@ Thread.Sleep(TimeSpan.FromSeconds(1));
5050
span.End();
5151
```
5252

53+
### Using Prometheus exporter
54+
55+
Configure Prometheus exporter to have stats collected by Prometheus.
56+
57+
1. Get Prometheus using [getting started guide][prometheus-get-started].
58+
2. Start `PrometheusExporter` as below.
59+
3. See [sample][prometheus-sample] for example use.
60+
61+
``` csharp
62+
var exporter = new PrometheusExporter(
63+
new PrometheusExporterOptions()
64+
{
65+
Url = new Uri("http://localhost:9184/metrics/")
66+
},
67+
Stats.ViewManager);
68+
69+
exporter.Start();
70+
71+
try
72+
{
73+
// record metrics
74+
statsRecorder.NewMeasureMap().Put(VideoSize, values[0] * MiB).Record();
75+
}
76+
finally
77+
{
78+
exporter.Stop();
79+
}
80+
```
81+
5382
### Using Application Insights exporter
5483

5584
1. Create [Application Insights][ai-get-started] resource.
@@ -100,4 +129,6 @@ deprecate it for 18 months before removing it, if possible.
100129
[ai-get-started]: https://docs.microsoft.com/azure/application-insights
101130
[semver]: http://semver.org/
102131
[ai-sample]: https://github.com/census-instrumentation/opencensus-csharp/blob/develop/src/Samples/TestApplicationInsights.cs
103-
[zipkin-sample]: https://github.com/census-instrumentation/opencensus-csharp/blob/develop/src/Samples/TestZipkin.cs
132+
[zipkin-sample]: https://github.com/census-instrumentation/opencensus-csharp/blob/develop/src/Samples/TestZipkin.cs
133+
[prometheus-get-started]: https://prometheus.io/docs/introduction/first_steps/
134+
[prometheus-sample]: https://github.com/census-instrumentation/opencensus-csharp/blob/develop/src/Samples/TestPrometheus.cs

src/OpenCensus.Exporter.ApplicationInsights/ApplicationInsightsExporter.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ public class ApplicationInsightsExporter
3131
{
3232
private const string TraceExporterName = "ApplicationInsightsTraceExporter";
3333

34-
private const string MetricsExporterName = "ApplicationInsightsMetricsExporter";
35-
3634
private readonly TelemetryConfiguration telemetryConfiguration;
3735

3836
private readonly IViewManager viewManager;
@@ -45,6 +43,8 @@ public class ApplicationInsightsExporter
4543

4644
private CancellationTokenSource tokenSource;
4745

46+
private Task workerThread;
47+
4848
/// <summary>
4949
/// Instantiates a new instance of an exporter from Open Census to Azure Application Insights.
5050
/// </summary>
@@ -79,7 +79,7 @@ public void Start()
7979
CancellationToken token = this.tokenSource.Token;
8080

8181
var metricsExporter = new MetricsExporterThread(this.telemetryConfiguration, this.viewManager, token, TimeSpan.FromMinutes(1));
82-
Task.Factory.StartNew((Action)metricsExporter.WorkerThread, TaskCreationOptions.LongRunning);
82+
this.workerThread = Task.Factory.StartNew((Action)metricsExporter.WorkerThread, TaskCreationOptions.LongRunning);
8383
}
8484
}
8585

@@ -97,6 +97,7 @@ public void Stop()
9797

9898
this.exportComponent.SpanExporter.UnregisterHandler(TraceExporterName);
9999
this.tokenSource.Cancel();
100+
this.workerThread.Wait();
100101
this.tokenSource = null;
101102

102103
this.handler = null;

src/OpenCensus.Exporter.ApplicationInsights/Implementation/MetricsExporterThread.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ internal void Export()
140140
{
141141
if (combined is IMeanData mean)
142142
{
143+
metricTelemetry.Sum = mean.Mean * mean.Count;
144+
metricTelemetry.Count = (int)mean.Count;
145+
metricTelemetry.Max = mean.Max;
146+
metricTelemetry.Min = mean.Min;
143147
}
144148

145149
return null;
@@ -148,7 +152,8 @@ internal void Export()
148152
{
149153
if (combined is IDistributionData dist)
150154
{
151-
metricTelemetry.Sum = dist.Mean;
155+
metricTelemetry.Sum = dist.Mean * dist.Count;
156+
metricTelemetry.Count = (int)dist.Count;
152157
metricTelemetry.Min = dist.Min;
153158
metricTelemetry.Max = dist.Max;
154159
metricTelemetry.StandardDeviation = dist.SumOfSquaredDeviations;
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// <copyright file="MetricsHttpServer.cs" company="OpenCensus Authors">
2+
// Copyright 2018, OpenCensus Authors
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of theLicense at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
// </copyright>
16+
17+
namespace OpenCensus.Exporter.Prometheus.Implementation
18+
{
19+
using System;
20+
using System.Diagnostics;
21+
using System.IO;
22+
using System.Net;
23+
using System.Threading;
24+
using OpenCensus.Stats;
25+
using OpenCensus.Stats.Aggregations;
26+
27+
internal class MetricsHttpServer
28+
{
29+
private readonly IViewManager viewManager;
30+
31+
private readonly CancellationToken token;
32+
33+
private readonly HttpListener httpListener = new HttpListener();
34+
35+
public MetricsHttpServer(IViewManager viewManager, PrometheusExporterOptions options, CancellationToken token)
36+
{
37+
this.viewManager = viewManager;
38+
this.token = token;
39+
this.httpListener.Prefixes.Add(options.Url.ToString());
40+
}
41+
42+
public void WorkerThread()
43+
{
44+
this.httpListener.Start();
45+
46+
try
47+
{
48+
while (!this.token.IsCancellationRequested)
49+
{
50+
var ctxTask = this.httpListener.GetContextAsync();
51+
ctxTask.Wait(this.token);
52+
53+
var ctx = ctxTask.Result;
54+
55+
ctx.Response.StatusCode = 200;
56+
ctx.Response.ContentType = PrometheusMetricBuilder.ContentType;
57+
58+
using (var output = ctx.Response.OutputStream)
59+
{
60+
using (var writer = new StreamWriter(output))
61+
{
62+
foreach (var view in this.viewManager.AllExportedViews)
63+
{
64+
var data = this.viewManager.GetView(view.Name);
65+
66+
var builder = new PrometheusMetricBuilder()
67+
.WithName(data.View.Name.AsString)
68+
.WithDescription(data.View.Description);
69+
70+
builder = data.View.Aggregation.Match<PrometheusMetricBuilder>(
71+
(agg) => { return builder.WithType("gauge"); }, // Func<ISum, M> p0
72+
(agg) => { return builder.WithType("counter"); }, // Func< ICount, M > p1,
73+
(agg) => { return builder.WithType("histogram"); }, // Func<IMean, M> p2,
74+
(agg) => { return builder.WithType("histogram"); }, // Func< IDistribution, M > p3,
75+
(agg) => { return builder.WithType("gauge"); }, // Func<ILastValue, M> p4,
76+
(agg) => { return builder.WithType("gauge"); }); // Func< IAggregation, M > p6);
77+
78+
foreach (var value in data.AggregationMap)
79+
{
80+
var metricValueBuilder = builder.AddValue();
81+
82+
// TODO: This is not optimal. Need to refactor to split builder into separate functions
83+
metricValueBuilder = value.Value.Match<PrometheusMetricBuilder.PrometheusMetricValueBuilder>(
84+
metricValueBuilder.WithValue,
85+
metricValueBuilder.WithValue,
86+
metricValueBuilder.WithValue,
87+
metricValueBuilder.WithValue,
88+
metricValueBuilder.WithValue,
89+
metricValueBuilder.WithValue,
90+
metricValueBuilder.WithValue,
91+
metricValueBuilder.WithValue);
92+
93+
for (int i = 0; i < value.Key.Values.Count; i++)
94+
{
95+
metricValueBuilder.WithLabel(data.View.Columns[i].Name, value.Key.Values[i].AsString);
96+
}
97+
}
98+
99+
builder.Write(writer);
100+
}
101+
}
102+
}
103+
}
104+
}
105+
catch (OperationCanceledException)
106+
{
107+
// this will happen when cancellation will be requested
108+
}
109+
catch (Exception)
110+
{
111+
// TODO: report error
112+
}
113+
finally
114+
{
115+
this.httpListener.Stop();
116+
this.httpListener.Close();
117+
}
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)