This repository has been archived by the owner on Dec 18, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introducing Stackdriver Exporter for traces (#48)
* Introducing Stackdriver Exporter for Opencensus C# library - Current implementation can only store string values - Added the exporter and trace handler only - The exporter relies on newest Trace API from Stackdriver. * Updating translation from ISpan to Stackdriver's Span to cover more fields * Fixing the issue that prevented Stackdriver API call to succeed: now construction of Span resource is taken care of by SpanName class that is part of Stackdriver Trace V2 API.
- Loading branch information
1 parent
a32e580
commit f9a47eb
Showing
10 changed files
with
308 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
src/OpenCensus.Exporter.Stackdriver/Implementation/StackdriverTraceExporter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
| ||
namespace OpenCensus.Exporter.Stackdriver.Implementation | ||
{ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Google.Cloud.Trace.V2; | ||
using OpenCensus.Exporter.Stackdriver.Utils; | ||
using OpenCensus.Trace; | ||
using OpenCensus.Trace.Export; | ||
|
||
static class SpanExtensions | ||
{ | ||
/// <summary> | ||
/// Translating <see cref="ISpanData"/> to Stackdriver's Span | ||
/// According to <see cref="https://cloud.google.com/trace/docs/reference/v2/rpc/google.devtools.cloudtrace.v2"/> specifications | ||
/// </summary> | ||
/// <param name="spanData">Span in OpenCensus format</param> | ||
/// <param name="projectId">Google Cloud Platform Project Id</param> | ||
/// <returns></returns> | ||
public static Span ToSpan(this ISpanData spanData, string projectId) | ||
{ | ||
string spanId = spanData.Context.SpanId.ToLowerBase16(); | ||
var span = new Span | ||
{ | ||
SpanName = new SpanName(projectId, spanData.Context.TraceId.ToLowerBase16(), spanId), | ||
SpanId = spanId, | ||
DisplayName = new TruncatableString { Value = spanData.Name }, | ||
StartTime = spanData.StartTimestamp.ToTimestamp(), | ||
EndTime = spanData.EndTimestamp.ToTimestamp(), | ||
ChildSpanCount = spanData.ChildSpanCount, | ||
}; | ||
|
||
if (spanData.Attributes != null) | ||
{ | ||
span.Attributes = new Span.Types.Attributes | ||
{ | ||
DroppedAttributesCount = spanData.Attributes != null ? spanData.Attributes.DroppedAttributesCount : 0, | ||
|
||
AttributeMap = { spanData.Attributes?.AttributeMap?.ToDictionary( | ||
s => s.Key, | ||
s => s.Value?.ToAttributeValue()) }, | ||
}; | ||
} | ||
|
||
if (spanData.ParentSpanId != null) | ||
{ | ||
string parentSpanId = spanData.ParentSpanId.ToLowerBase16(); | ||
if (!string.IsNullOrEmpty(parentSpanId)) | ||
{ | ||
span.ParentSpanId = parentSpanId; | ||
} | ||
} | ||
|
||
return span; | ||
} | ||
|
||
public static Google.Cloud.Trace.V2.AttributeValue ToAttributeValue(this IAttributeValue av) | ||
{ | ||
// TODO Currently we assume we store only strings. | ||
return new Google.Cloud.Trace.V2.AttributeValue | ||
{ | ||
StringValue = new TruncatableString | ||
{ | ||
Value = av.Match( | ||
s => s, | ||
b => b.ToString(), | ||
l => l.ToString(), | ||
obj => obj.ToString(), | ||
obj => obj.ToString()) | ||
} | ||
}; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Exports a group of spans to Stackdriver | ||
/// </summary> | ||
class StackdriverTraceExporter : IHandler | ||
{ | ||
private Google.Api.Gax.ResourceNames.ProjectName googleCloudProjectId; | ||
|
||
public StackdriverTraceExporter(string projectId) | ||
{ | ||
googleCloudProjectId = new Google.Api.Gax.ResourceNames.ProjectName(projectId); | ||
|
||
} | ||
|
||
public void Export(IList<ISpanData> spanDataList) | ||
{ | ||
TraceServiceClient traceWriter = TraceServiceClient.Create(); | ||
var batchSpansRequest = new BatchWriteSpansRequest | ||
{ | ||
ProjectName = googleCloudProjectId, | ||
Spans = { spanDataList.Select(s => s.ToSpan(googleCloudProjectId.ProjectId)) }, | ||
}; | ||
|
||
traceWriter.BatchWriteSpans(batchSpansRequest); | ||
} | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
src/OpenCensus.Exporter.Stackdriver/OpenCensus.Exporter.Stackdriver.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<!-- | ||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'OpenCensus.sln'))\build\Common.prod.props" /> | ||
--> | ||
<PropertyGroup> | ||
<TargetFramework>netstandard2.0</TargetFramework> | ||
<IncludeSymbols>True</IncludeSymbols> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup> | ||
<Description>Stackdriver Exporter for OpenCensus.</Description> | ||
<PackageTags>Tracing;OpenCensus;Management;Monitoring;Stackdriver;Google;GCP;distributed-tracing</PackageTags> | ||
<PackageIconUrl>https://opencensus.io/images/opencensus-logo.png</PackageIconUrl> | ||
<PackageProjectUrl>https://opencensus.io</PackageProjectUrl> | ||
<PackageLicenseUrl>https://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl> | ||
<Authors>OpenCensus authors</Authors> | ||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Google.Cloud.Trace.V2" Version="1.0.0-beta02" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\OpenCensus.Abstractions\OpenCensus.Abstractions.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
70 changes: 70 additions & 0 deletions
70
src/OpenCensus.Exporter.Stackdriver/StackdriverExporter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
| ||
// <copyright file="StackdriverExporter.cs" company="OpenCensus Authors"> | ||
// Copyright 2018, OpenCensus Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of theLicense at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// </copyright> | ||
|
||
namespace OpenCensus.Exporter.Stackdriver | ||
{ | ||
using OpenCensus.Exporter.Stackdriver.Implementation; | ||
using OpenCensus.Trace.Export; | ||
using System; | ||
using System.Threading; | ||
|
||
public class StackdriverExporter | ||
{ | ||
private const string ExporterName = "StackdriverTraceExporter"; | ||
|
||
private readonly IExportComponent exportComponent; | ||
private readonly string projectId; | ||
private object locker = new object(); | ||
private bool isInitialized = false; | ||
|
||
public StackdriverExporter(string projectId, IExportComponent exportComponent) | ||
{ | ||
this.projectId = projectId; | ||
this.exportComponent = exportComponent; | ||
} | ||
|
||
public void Start() | ||
{ | ||
lock (locker) | ||
{ | ||
if (isInitialized) | ||
{ | ||
return; | ||
} | ||
|
||
var traceExporter = new StackdriverTraceExporter(projectId); | ||
exportComponent.SpanExporter.RegisterHandler(ExporterName, traceExporter); | ||
|
||
isInitialized = true; | ||
} | ||
} | ||
|
||
public void Stop() | ||
{ | ||
lock (locker) | ||
{ | ||
if (!isInitialized) | ||
{ | ||
return; | ||
} | ||
|
||
exportComponent.SpanExporter.UnregisterHandler(ExporterName); | ||
isInitialized = false; | ||
} | ||
} | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/OpenCensus.Exporter.Stackdriver/Utils/ProtoExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
| ||
namespace OpenCensus.Exporter.Stackdriver.Utils | ||
{ | ||
using Google.Protobuf.WellKnownTypes; | ||
using OpenCensus.Common; | ||
|
||
public static class ProtoExtensions | ||
{ | ||
public static Timestamp ToTimestamp(this ITimestamp timestamp) | ||
{ | ||
return new Timestamp { Seconds = timestamp.Seconds, Nanos = timestamp.Nanos }; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
namespace Samples | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using OpenCensus.Exporter.Stackdriver; | ||
using OpenCensus.Stats; | ||
using OpenCensus.Stats.Aggregations; | ||
using OpenCensus.Stats.Measures; | ||
using OpenCensus.Tags; | ||
using OpenCensus.Trace; | ||
using OpenCensus.Trace.Sampler; | ||
|
||
internal class TestStackdriver | ||
{ | ||
private static ITracer tracer = Tracing.Tracer; | ||
private static ITagger tagger = Tags.Tagger; | ||
|
||
private static IStatsRecorder statsRecorder = Stats.StatsRecorder; | ||
private static readonly IMeasureLong VideoSize = MeasureLong.Create("my.org/measure/video_size", "size of processed videos", "By"); | ||
private static readonly ITagKey FrontendKey = TagKey.Create("my.org/keys/frontend"); | ||
|
||
private static long MiB = 1 << 20; | ||
|
||
private static readonly IViewName VideoSizeViewName = ViewName.Create("my.org/views/video_size"); | ||
|
||
private static readonly IView VideoSizeView = View.Create( | ||
VideoSizeViewName, | ||
"processed video size over time", | ||
VideoSize, | ||
Distribution.Create(BucketBoundaries.Create(new List<double>() { 0.0, 16.0 * MiB, 256.0 * MiB })), | ||
new List<ITagKey>() { FrontendKey }); | ||
|
||
internal static void Run() | ||
{ | ||
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", @"C:\Users\zeltser\Downloads\aspnetcoreissue-1af8a0ca869b.json"); | ||
var exporter = new StackdriverExporter("aspnetcoreissue", Tracing.ExportComponent); | ||
exporter.Start(); | ||
|
||
ITagContextBuilder tagContextBuilder = tagger.CurrentBuilder.Put(FrontendKey, TagValue.Create("mobile-ios9.3.5")); | ||
|
||
var spanBuilder = tracer | ||
.SpanBuilder("incoming request") | ||
.SetRecordEvents(true) | ||
.SetSampler(Samplers.AlwaysSample); | ||
|
||
Stats.ViewManager.RegisterView(VideoSizeView); | ||
|
||
using (var scopedTags = tagContextBuilder.BuildScoped()) | ||
{ | ||
using (var scopedSpan = spanBuilder.StartScopedSpan()) | ||
{ | ||
tracer.CurrentSpan.AddAnnotation("Start processing video."); | ||
Thread.Sleep(TimeSpan.FromMilliseconds(10)); | ||
statsRecorder.NewMeasureMap().Put(VideoSize, 25 * MiB).Record(); | ||
tracer.CurrentSpan.AddAnnotation("Finished processing video."); | ||
} | ||
} | ||
|
||
Thread.Sleep(TimeSpan.FromMilliseconds(5100)); | ||
|
||
var viewData = Stats.ViewManager.GetView(VideoSizeViewName); | ||
|
||
Console.WriteLine(viewData); | ||
|
||
Console.WriteLine("Done... wait for events to arrive to backend!"); | ||
Console.ReadLine(); | ||
} | ||
} | ||
} |