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

Commit 5dac82f

Browse files
Exporter that pushes traces and metrics from to Application Insights (#34)
* first skeleton * wip * add project * populate few properties for AI tracer * support all metric types * few more properties read from Span * finish thread in Stop
1 parent ff0d82f commit 5dac82f

File tree

8 files changed

+464
-4
lines changed

8 files changed

+464
-4
lines changed

OpenCensus.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".vsts", ".vsts", "{61188153
3434
.vsts\ci-myget-update.yml = .vsts\ci-myget-update.yml
3535
EndProjectSection
3636
EndProject
37+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenCensus.Exporter.ApplicationInsights", "src\OpenCensus.Exporter.ApplicationInsights\OpenCensus.Exporter.ApplicationInsights.csproj", "{4493F5D9-874E-4FBF-B2F3-37890BD910E0}"
38+
EndProject
3739
Global
3840
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3941
Debug|Any CPU = Debug|Any CPU
@@ -52,6 +54,10 @@ Global
5254
{7EDAE7FA-B44E-42CA-80FA-7DF2FAA2C5DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
5355
{7EDAE7FA-B44E-42CA-80FA-7DF2FAA2C5DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
5456
{7EDAE7FA-B44E-42CA-80FA-7DF2FAA2C5DD}.Release|Any CPU.Build.0 = Release|Any CPU
57+
{4493F5D9-874E-4FBF-B2F3-37890BD910E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
58+
{4493F5D9-874E-4FBF-B2F3-37890BD910E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
59+
{4493F5D9-874E-4FBF-B2F3-37890BD910E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
60+
{4493F5D9-874E-4FBF-B2F3-37890BD910E0}.Release|Any CPU.Build.0 = Release|Any CPU
5561
EndGlobalSection
5662
GlobalSection(SolutionProperties) = preSolution
5763
HideSolutionNode = FALSE
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// <copyright file="ApplicationInsightsExporter.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.ApplicationInsights
18+
{
19+
using System;
20+
using System.Threading;
21+
using System.Threading.Tasks;
22+
using Microsoft.ApplicationInsights.Extensibility;
23+
using OpenCensus.Exporter.ApplicationInsights.Implementation;
24+
using OpenCensus.Stats;
25+
using OpenCensus.Trace.Export;
26+
27+
/// <summary>
28+
/// Exporter of Open Census traces and metrics to Azure Application Insights.
29+
/// </summary>
30+
public class ApplicationInsightsExporter
31+
{
32+
private const string TraceExporterName = "ApplicationInsightsTraceExporter";
33+
34+
private const string MetricsExporterName = "ApplicationInsightsMetricsExporter";
35+
36+
private readonly TelemetryConfiguration telemetryConfiguration;
37+
38+
private readonly IViewManager viewManager;
39+
40+
private readonly IExportComponent exportComponent;
41+
42+
private readonly object lck = new object();
43+
44+
private TraceExporterHandler handler;
45+
46+
private CancellationTokenSource tokenSource;
47+
48+
/// <summary>
49+
/// Instantiates a new instance of an exporter from Open Census to Azure Application Insights.
50+
/// </summary>
51+
/// <param name="telemetryConfiguration">Telemetry configuration to use to report telemetry.</param>
52+
/// <param name="exportComponent">Exporter to get traces and metrics from.</param>
53+
/// <param name="viewManager">View manager to get stats from.</param>
54+
public ApplicationInsightsExporter(TelemetryConfiguration telemetryConfiguration, IExportComponent exportComponent, IViewManager viewManager)
55+
{
56+
this.exportComponent = exportComponent;
57+
this.viewManager = viewManager;
58+
this.telemetryConfiguration = telemetryConfiguration;
59+
}
60+
61+
/// <summary>
62+
/// Start exporter.
63+
/// </summary>
64+
public void Start()
65+
{
66+
lock (this.lck)
67+
{
68+
if (this.handler != null)
69+
{
70+
return;
71+
}
72+
73+
this.handler = new TraceExporterHandler(this.telemetryConfiguration);
74+
75+
this.exportComponent.SpanExporter.RegisterHandler(TraceExporterName, this.handler);
76+
77+
this.tokenSource = new CancellationTokenSource();
78+
79+
CancellationToken token = this.tokenSource.Token;
80+
81+
var metricsExporter = new MetricsExporterThread(this.telemetryConfiguration, this.viewManager, token, TimeSpan.FromMinutes(1));
82+
Task.Factory.StartNew((Action)metricsExporter.WorkerThread, TaskCreationOptions.LongRunning);
83+
}
84+
}
85+
86+
/// <summary>
87+
/// Stop exporter.
88+
/// </summary>
89+
public void Stop()
90+
{
91+
lock (this.lck)
92+
{
93+
if (this.handler == null)
94+
{
95+
return;
96+
}
97+
98+
this.exportComponent.SpanExporter.UnregisterHandler(TraceExporterName);
99+
this.tokenSource.Cancel();
100+
this.tokenSource = null;
101+
102+
this.handler = null;
103+
}
104+
}
105+
}
106+
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
// <copyright file="MetricsExporterThread.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.ApplicationInsights.Implementation
18+
{
19+
using System;
20+
using System.Diagnostics;
21+
using System.Threading;
22+
using Microsoft.ApplicationInsights;
23+
using Microsoft.ApplicationInsights.DataContracts;
24+
using Microsoft.ApplicationInsights.Extensibility;
25+
using OpenCensus.Stats;
26+
using OpenCensus.Stats.Aggregations;
27+
28+
internal class MetricsExporterThread
29+
{
30+
private readonly IViewManager viewManager;
31+
32+
private readonly TelemetryClient telemetryClient;
33+
34+
private readonly TimeSpan collectionInterval = TimeSpan.FromSeconds(10);
35+
36+
private readonly TimeSpan cancellationInterval = TimeSpan.FromMilliseconds(10);
37+
38+
private readonly CancellationToken token;
39+
40+
public MetricsExporterThread(TelemetryConfiguration telemetryConfiguration, IViewManager viewManager, CancellationToken token, TimeSpan collectionInterval)
41+
{
42+
this.telemetryClient = new TelemetryClient(telemetryConfiguration);
43+
this.viewManager = viewManager;
44+
this.collectionInterval = collectionInterval;
45+
this.token = token;
46+
}
47+
48+
public void WorkerThread()
49+
{
50+
try
51+
{
52+
var sleepInterval = this.collectionInterval;
53+
Stopwatch sw = new Stopwatch();
54+
55+
while (!this.token.IsCancellationRequested)
56+
{
57+
sw.Start();
58+
this.Export();
59+
sw.Stop();
60+
61+
// adjust interval for data collection time
62+
sleepInterval = this.collectionInterval.Subtract(sw.Elapsed);
63+
64+
// allow faster thread cancellation
65+
while (sleepInterval > this.cancellationInterval && !this.token.IsCancellationRequested)
66+
{
67+
Thread.Sleep(this.cancellationInterval);
68+
sleepInterval.Subtract(this.cancellationInterval);
69+
}
70+
71+
Thread.Sleep(sleepInterval);
72+
}
73+
}
74+
catch (Exception)
75+
{
76+
// TODO: report error
77+
}
78+
}
79+
80+
internal void Export()
81+
{
82+
foreach (var view in this.viewManager.AllExportedViews)
83+
{
84+
var data = this.viewManager.GetView(view.Name);
85+
86+
foreach (var value in data.AggregationMap)
87+
{
88+
var metricTelemetry = new MetricTelemetry
89+
{
90+
Name = data.View.Name.AsString
91+
};
92+
93+
for (int i = 0; i < value.Key.Values.Count; i++)
94+
{
95+
var name = data.View.Columns[i].Name;
96+
var val = value.Key.Values[i].AsString;
97+
metricTelemetry.Properties.Add(name, val);
98+
}
99+
100+
// Now those propertis needs to be populated.
101+
//
102+
// metricTelemetry.Sum
103+
// metricTelemetry.Count
104+
// metricTelemetry.Max
105+
// metricTelemetry.Min
106+
// metricTelemetry.StandardDeviation
107+
//
108+
// See data model for clarification on the meaning of those fields.
109+
// https://docs.microsoft.com/azure/application-insights/application-insights-data-model-metric-telemetry
110+
111+
value.Value.Match<object>(
112+
(combined) =>
113+
{
114+
if (combined is ISumDataDouble sum)
115+
{
116+
metricTelemetry.Sum = sum.Sum;
117+
}
118+
return null;
119+
},
120+
(combined) =>
121+
{
122+
if (combined is ISumDataLong sum)
123+
{
124+
metricTelemetry.Sum = sum.Sum;
125+
}
126+
return null;
127+
},
128+
(combined) =>
129+
{
130+
if (combined is ICountData count)
131+
{
132+
metricTelemetry.Sum = count.Count;
133+
}
134+
return null;
135+
},
136+
(combined) =>
137+
{
138+
if (combined is IMeanData mean)
139+
{
140+
}
141+
return null;
142+
},
143+
(combined) =>
144+
{
145+
if (combined is IDistributionData dist)
146+
{
147+
metricTelemetry.Sum = dist.Mean;
148+
metricTelemetry.Min = dist.Min;
149+
metricTelemetry.Max = dist.Max;
150+
metricTelemetry.StandardDeviation = dist.SumOfSquaredDeviations;
151+
}
152+
153+
return null;
154+
},
155+
(combined) =>
156+
{
157+
if (combined is ILastValueDataDouble lastValue)
158+
{
159+
metricTelemetry.Sum = lastValue.LastValue;
160+
}
161+
return null;
162+
},
163+
(combined) =>
164+
{
165+
if (combined is ILastValueDataLong lastValue)
166+
{
167+
metricTelemetry.Sum = lastValue.LastValue;
168+
}
169+
return null;
170+
},
171+
(combined) =>
172+
{
173+
if (combined is IAggregationData aggregationData)
174+
{
175+
// TODO: report an error
176+
}
177+
return null;
178+
});
179+
this.telemetryClient.TrackMetric(metricTelemetry);
180+
}
181+
182+
Console.WriteLine(view);
183+
Console.WriteLine(data);
184+
}
185+
}
186+
}
187+
}

0 commit comments

Comments
 (0)