Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opentelemetry Spans API #975

Merged
merged 1 commit into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Text.RegularExpressions;
using GxClasses.Helpers;

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

private static string OPENTELEMETRY_SERVICE = "Observability";
public static string GX_ACTIVITY_SOURCE_NAME = "GeneXus.Tracing";

const string OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES";
const string OTEL_SERVICE_NAME = "OTEL_SERVICE_NAME";
const string OTEL_SERVICE_VERSION = "OTEL_SERVICE_VERSION";
const string OPENTELEMETRY_SERVICE = "Observability";

public static string GX_ACTIVITY_SOURCE_NAME= GetServiceNameValue(OTEL_RESOURCE_ATTRIBUTES);
public static string GX_ACTIVITY_SOURCE_VERSION= GetServiceVersionValue(OTEL_RESOURCE_ATTRIBUTES);

private static string GetServiceNameValue(string input)
{
string otelServiceNameEnvVar = Environment.GetEnvironmentVariable(OTEL_SERVICE_NAME);
if (!string.IsNullOrEmpty(otelServiceNameEnvVar))
return otelServiceNameEnvVar;

string pattern = @"(?:\b\w+\b=\w+)(?:,(?:\b\w+\b=\w+))*";
MatchCollection matches = Regex.Matches(input, pattern);

foreach (Match match in matches)
{
string[] keyValue = match.Value.Split('=');

if (keyValue[0] == "service.name")
{
return keyValue[1];
}
}
return "GeneXus.Tracing";
}
private static string GetServiceVersionValue(string input)
{
string otelServiceNameEnvVar = Environment.GetEnvironmentVariable(OTEL_SERVICE_VERSION);
if (!string.IsNullOrEmpty(otelServiceNameEnvVar))
return otelServiceNameEnvVar;

string pattern = @"(?:\b\w+\b=\w+)(?:,(?:\b\w+\b=\w+))*";
MatchCollection matches = Regex.Matches(input, pattern);

foreach (Match match in matches)
{
string[] keyValue = match.Value.Split('=');

if (keyValue[0] == "service.version")
{
return keyValue[1];
}
}
return string.Empty;
}
private static IOpenTelemetryProvider GetOpenTelemetryProvider()
{
IOpenTelemetryProvider otelProvider = null;
Expand All @@ -34,7 +80,7 @@ private static IOpenTelemetryProvider GetOpenTelemetryProvider()
}
catch (Exception e)
{
GXLogging.Error(log, "Couldn´t create OpenTelemetry provider.", e.Message, e);
GXLogging.Error(log, "Couldn't create OpenTelemetry provider.", e.Message, e);
throw e;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,112 +1,183 @@
using System;
using System.Diagnostics;
using GeneXus.Application;
using GeneXus.Attributes;
using OpenTelemetry;
using OpenTelemetry.Trace;
using static GeneXus.OpenTelemetry.Diagnostics.OtelTracer;

namespace GeneXus.OpenTelemetry.Diagnostics
{
[GXApi]
public class OtelSpan
{
private Activity _activity;

public enum SpanStatusCode
{
Unset,
Ok,
Error
}
public string Id
{ get => _activity?.Id; }

public bool IsAllDataRequested
internal OtelSpan(Activity activity)
{
get
{
if (_activity != null)
return _activity.IsAllDataRequested;
return false;
}
_activity = activity;
}

public bool IsStopped
{ get
{
if (_activity != null )
return _activity.IsStopped;
return false;
}
}
public OtelSpan()
{}

public short Kind
{ get => (short)_activity?.Kind; }
public Activity Activity => _activity;

public string ParentId
{ get => _activity?.ParentId; }
#region EO Properties
public GXSpanContext SpanContext => _activity == null ? null : new GXSpanContext(_activity.Context);

public string ParentSpanId
{ get => _activity?.ParentSpanId.ToString(); }
public GXTraceContext GetContext => _activity == null ? null : new GXTraceContext(_activity.Context);
public string SpanId => _activity?.Id;

public string TraceId
{ get => _activity?.TraceId.ToString(); }
public string TraceId => _activity?.TraceId.ToHexString();

public short Status
{ get => (short)_activity?.Status; }

internal OtelSpan(Activity activity)
#endregion

#region Methods
public void Stop()
{
_activity = activity;
_activity?.Stop();
}
public void RecordException(string message)
{
_activity?.RecordException(new Exception(message));
}

public OtelSpan()
public void SetStringAttribute(string property, string value)
{
_activity = Activity.Current;
_activity?.SetTag(property, value);

}
public void Start()
public void SetLongAttribute(string property, long value)
{
_activity?.Start();
_activity?.SetTag(property, value);

}
public void SetDoubleAttribute(string property, double value)
{
_activity?.SetTag(property, value);

public void Stop()
}
public void SetBooleanAttribute(string property, bool value)
{
_activity?.Stop();
_activity?.SetTag(property, value);

}
public void RecordException(string message)
public GXTraceContext AddBaggage(string property, string value)
{
Baggage.SetBaggage(property, value);
if (_activity != null)
return new GXTraceContext(_activity.Context);
else return null;
}

public string GetBaggageItem(string property,GXTraceContext gXTraceContext)
{
return Baggage.GetBaggage(property);
}
public void SetStatus(SpanStatusCode spanStatusCode, string message)
{
_activity.RecordException(new Exception(message));
_activity?.SetStatus((ActivityStatusCode)spanStatusCode, message);
}
public void SetStatus(SpanStatusCode spanStatusCode)
{
_activity?.SetStatus((ActivityStatusCode)spanStatusCode);
}

#endregion

public void SetTag(string property, string value)
#region Private Methods
public bool IsRecording => IsSpanRecording();

private bool IsSpanRecording()
{
_activity.SetTag(property, value);
if (_activity != null)
return _activity.IsAllDataRequested;
else
return false;
}
public string GetTagItem(string property)
#endregion

}

public class GXTraceContext : GXSpanContext
{
//Dummy class to be compatible with Java.
//.NET does not requiere propagating the context explicitly in most of the cases.
//https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Api/README.md#baggage-api

public GXTraceContext(ActivityContext activityContext):base(activityContext) { }
public GXTraceContext():base() { }
}
public class GXSpanContext
{
private ActivityContext _activityContext;
public GXSpanContext()
{
return _activity.GetTagItem(property).ToString();
_activityContext = Activity.Current.Context;
}
public void AddBaggage(string property, string value)

public GXSpanContext(ActivityContext activityContext)
{
_activity.AddBaggage(property, value);
_activityContext = activityContext;
}
public string GetBaggageItem(string property)
public ActivityContext ActivityContext { get { return _activityContext; } }

public string TraceId => GetTraceId();

public string SpanId => GetSpanId();

private string GetTraceId()
{
return _activity.GetBaggageItem(property).ToString();
if (_activityContext != null)
{
ActivityTraceId activityTraceId = _activityContext.TraceId;
return activityTraceId.ToHexString();
} else return null;
}
private string GetSpanId()
{
if (_activityContext != null)
{
ActivitySpanId activitySpanId = _activityContext.SpanId;
return activitySpanId.ToHexString();
} else { return null; }
}
public void SetStatus(SpanStatusCode spanStatusCode, string message)
private GXActivityTraceFlags TraceFlags()
{
_activity.SetStatus((ActivityStatusCode)spanStatusCode, message);
if (_activityContext != null) {
ActivityTraceFlags activityTraceFlags = _activityContext.TraceFlags;
return (GXActivityTraceFlags)activityTraceFlags;
}
else { return GXActivityTraceFlags.None;}
}

public SpanStatusCode GetStatus()
private string TraceState()
{
return (SpanStatusCode)_activity.GetStatus().StatusCode;
if (_activityContext != null)
return _activityContext.TraceState;
else return null;
}

//ToDO
//public void AddEvent()
//{

//}
//
// Summary:
// Specifies flags defined by the W3C standard that are associated with an activity.

internal enum GXActivityTraceFlags
{
//
// Summary:
// The activity has not been marked.
None = 0,
//
// Summary:
// The activity (or more likely its parents) has been marked as useful to record.
Recorded = 1
}
}
}
Loading
Loading