Skip to content

Commit 24903cd

Browse files
authored
Opentelemetry Spans API (#975)
1 parent 70773cd commit 24903cd

File tree

3 files changed

+255
-70
lines changed

3 files changed

+255
-70
lines changed

dotnet/src/dotnetcore/GxClasses/Services/OpenTelemetry/OpenTelemetryService.cs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Text.RegularExpressions;
23
using GxClasses.Helpers;
34

45
namespace GeneXus.Services.OpenTelemetry
@@ -12,9 +13,54 @@ public static class OpenTelemetryService
1213
{
1314
private static readonly IGXLogger log = GXLoggerFactory.GetLogger(typeof(OpenTelemetryService).FullName);
1415

15-
private static string OPENTELEMETRY_SERVICE = "Observability";
16-
public static string GX_ACTIVITY_SOURCE_NAME = "GeneXus.Tracing";
17-
16+
const string OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES";
17+
const string OTEL_SERVICE_NAME = "OTEL_SERVICE_NAME";
18+
const string OTEL_SERVICE_VERSION = "OTEL_SERVICE_VERSION";
19+
const string OPENTELEMETRY_SERVICE = "Observability";
20+
21+
public static string GX_ACTIVITY_SOURCE_NAME= GetServiceNameValue(OTEL_RESOURCE_ATTRIBUTES);
22+
public static string GX_ACTIVITY_SOURCE_VERSION= GetServiceVersionValue(OTEL_RESOURCE_ATTRIBUTES);
23+
24+
private static string GetServiceNameValue(string input)
25+
{
26+
string otelServiceNameEnvVar = Environment.GetEnvironmentVariable(OTEL_SERVICE_NAME);
27+
if (!string.IsNullOrEmpty(otelServiceNameEnvVar))
28+
return otelServiceNameEnvVar;
29+
30+
string pattern = @"(?:\b\w+\b=\w+)(?:,(?:\b\w+\b=\w+))*";
31+
MatchCollection matches = Regex.Matches(input, pattern);
32+
33+
foreach (Match match in matches)
34+
{
35+
string[] keyValue = match.Value.Split('=');
36+
37+
if (keyValue[0] == "service.name")
38+
{
39+
return keyValue[1];
40+
}
41+
}
42+
return "GeneXus.Tracing";
43+
}
44+
private static string GetServiceVersionValue(string input)
45+
{
46+
string otelServiceNameEnvVar = Environment.GetEnvironmentVariable(OTEL_SERVICE_VERSION);
47+
if (!string.IsNullOrEmpty(otelServiceNameEnvVar))
48+
return otelServiceNameEnvVar;
49+
50+
string pattern = @"(?:\b\w+\b=\w+)(?:,(?:\b\w+\b=\w+))*";
51+
MatchCollection matches = Regex.Matches(input, pattern);
52+
53+
foreach (Match match in matches)
54+
{
55+
string[] keyValue = match.Value.Split('=');
56+
57+
if (keyValue[0] == "service.version")
58+
{
59+
return keyValue[1];
60+
}
61+
}
62+
return string.Empty;
63+
}
1864
private static IOpenTelemetryProvider GetOpenTelemetryProvider()
1965
{
2066
IOpenTelemetryProvider otelProvider = null;
@@ -34,7 +80,7 @@ private static IOpenTelemetryProvider GetOpenTelemetryProvider()
3480
}
3581
catch (Exception e)
3682
{
37-
GXLogging.Error(log, "Couldn´t create OpenTelemetry provider.", e.Message, e);
83+
GXLogging.Error(log, "Couldn't create OpenTelemetry provider.", e.Message, e);
3884
throw e;
3985
}
4086
}
Lines changed: 128 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,183 @@
11
using System;
22
using System.Diagnostics;
3-
using GeneXus.Application;
3+
using GeneXus.Attributes;
4+
using OpenTelemetry;
45
using OpenTelemetry.Trace;
5-
using static GeneXus.OpenTelemetry.Diagnostics.OtelTracer;
66

77
namespace GeneXus.OpenTelemetry.Diagnostics
88
{
9+
[GXApi]
910
public class OtelSpan
1011
{
1112
private Activity _activity;
12-
1313
public enum SpanStatusCode
1414
{
1515
Unset,
1616
Ok,
1717
Error
1818
}
19-
public string Id
20-
{ get => _activity?.Id; }
2119

22-
public bool IsAllDataRequested
20+
internal OtelSpan(Activity activity)
2321
{
24-
get
25-
{
26-
if (_activity != null)
27-
return _activity.IsAllDataRequested;
28-
return false;
29-
}
22+
_activity = activity;
3023
}
3124

32-
public bool IsStopped
33-
{ get
34-
{
35-
if (_activity != null )
36-
return _activity.IsStopped;
37-
return false;
38-
}
39-
}
25+
public OtelSpan()
26+
{}
4027

41-
public short Kind
42-
{ get => (short)_activity?.Kind; }
28+
public Activity Activity => _activity;
4329

44-
public string ParentId
45-
{ get => _activity?.ParentId; }
30+
#region EO Properties
31+
public GXSpanContext SpanContext => _activity == null ? null : new GXSpanContext(_activity.Context);
4632

47-
public string ParentSpanId
48-
{ get => _activity?.ParentSpanId.ToString(); }
33+
public GXTraceContext GetContext => _activity == null ? null : new GXTraceContext(_activity.Context);
34+
public string SpanId => _activity?.Id;
4935

50-
public string TraceId
51-
{ get => _activity?.TraceId.ToString(); }
36+
public string TraceId => _activity?.TraceId.ToHexString();
5237

53-
public short Status
54-
{ get => (short)_activity?.Status; }
55-
56-
internal OtelSpan(Activity activity)
38+
#endregion
39+
40+
#region Methods
41+
public void Stop()
5742
{
58-
_activity = activity;
43+
_activity?.Stop();
44+
}
45+
public void RecordException(string message)
46+
{
47+
_activity?.RecordException(new Exception(message));
5948
}
6049

61-
public OtelSpan()
50+
public void SetStringAttribute(string property, string value)
6251
{
63-
_activity = Activity.Current;
52+
_activity?.SetTag(property, value);
53+
6454
}
65-
public void Start()
55+
public void SetLongAttribute(string property, long value)
6656
{
67-
_activity?.Start();
57+
_activity?.SetTag(property, value);
58+
6859
}
60+
public void SetDoubleAttribute(string property, double value)
61+
{
62+
_activity?.SetTag(property, value);
6963

70-
public void Stop()
64+
}
65+
public void SetBooleanAttribute(string property, bool value)
7166
{
72-
_activity?.Stop();
67+
_activity?.SetTag(property, value);
68+
7369
}
74-
public void RecordException(string message)
70+
public GXTraceContext AddBaggage(string property, string value)
71+
{
72+
Baggage.SetBaggage(property, value);
73+
if (_activity != null)
74+
return new GXTraceContext(_activity.Context);
75+
else return null;
76+
}
77+
78+
public string GetBaggageItem(string property,GXTraceContext gXTraceContext)
79+
{
80+
return Baggage.GetBaggage(property);
81+
}
82+
public void SetStatus(SpanStatusCode spanStatusCode, string message)
7583
{
76-
_activity.RecordException(new Exception(message));
84+
_activity?.SetStatus((ActivityStatusCode)spanStatusCode, message);
7785
}
86+
public void SetStatus(SpanStatusCode spanStatusCode)
87+
{
88+
_activity?.SetStatus((ActivityStatusCode)spanStatusCode);
89+
}
90+
91+
#endregion
7892

79-
public void SetTag(string property, string value)
93+
#region Private Methods
94+
public bool IsRecording => IsSpanRecording();
95+
96+
private bool IsSpanRecording()
8097
{
81-
_activity.SetTag(property, value);
98+
if (_activity != null)
99+
return _activity.IsAllDataRequested;
100+
else
101+
return false;
82102
}
83-
public string GetTagItem(string property)
103+
#endregion
104+
105+
}
106+
107+
public class GXTraceContext : GXSpanContext
108+
{
109+
//Dummy class to be compatible with Java.
110+
//.NET does not requiere propagating the context explicitly in most of the cases.
111+
//https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Api/README.md#baggage-api
112+
113+
public GXTraceContext(ActivityContext activityContext):base(activityContext) { }
114+
public GXTraceContext():base() { }
115+
}
116+
public class GXSpanContext
117+
{
118+
private ActivityContext _activityContext;
119+
public GXSpanContext()
84120
{
85-
return _activity.GetTagItem(property).ToString();
121+
_activityContext = Activity.Current.Context;
86122
}
87-
public void AddBaggage(string property, string value)
123+
124+
public GXSpanContext(ActivityContext activityContext)
88125
{
89-
_activity.AddBaggage(property, value);
126+
_activityContext = activityContext;
90127
}
91-
public string GetBaggageItem(string property)
128+
public ActivityContext ActivityContext { get { return _activityContext; } }
129+
130+
public string TraceId => GetTraceId();
131+
132+
public string SpanId => GetSpanId();
133+
134+
private string GetTraceId()
92135
{
93-
return _activity.GetBaggageItem(property).ToString();
136+
if (_activityContext != null)
137+
{
138+
ActivityTraceId activityTraceId = _activityContext.TraceId;
139+
return activityTraceId.ToHexString();
140+
} else return null;
141+
}
142+
private string GetSpanId()
143+
{
144+
if (_activityContext != null)
145+
{
146+
ActivitySpanId activitySpanId = _activityContext.SpanId;
147+
return activitySpanId.ToHexString();
148+
} else { return null; }
94149
}
95-
public void SetStatus(SpanStatusCode spanStatusCode, string message)
150+
private GXActivityTraceFlags TraceFlags()
96151
{
97-
_activity.SetStatus((ActivityStatusCode)spanStatusCode, message);
152+
if (_activityContext != null) {
153+
ActivityTraceFlags activityTraceFlags = _activityContext.TraceFlags;
154+
return (GXActivityTraceFlags)activityTraceFlags;
155+
}
156+
else { return GXActivityTraceFlags.None;}
98157
}
99158

100-
public SpanStatusCode GetStatus()
159+
private string TraceState()
101160
{
102-
return (SpanStatusCode)_activity.GetStatus().StatusCode;
161+
if (_activityContext != null)
162+
return _activityContext.TraceState;
163+
else return null;
103164
}
104165

105-
//ToDO
106-
//public void AddEvent()
107-
//{
108166

109-
//}
167+
//
168+
// Summary:
169+
// Specifies flags defined by the W3C standard that are associated with an activity.
110170

171+
internal enum GXActivityTraceFlags
172+
{
173+
//
174+
// Summary:
175+
// The activity has not been marked.
176+
None = 0,
177+
//
178+
// Summary:
179+
// The activity (or more likely its parents) has been marked as useful to record.
180+
Recorded = 1
181+
}
111182
}
112183
}

0 commit comments

Comments
 (0)