3 Commits
Author SHA1 Message Date
Stevan Freeborn 0dac827923 Merge pull request #6 from StevanFreeborn/stevanfreeborn/feat/add-otel-to-api
feat: setup otel and send to seq
2025-06-07 14:15:01 -05:00
GitHub Actions 8338e26b88 chore: format fixes [skip ci] 2025-06-07 19:13:57 +00:00
Stevan Freeborn 4fd1741556 feat: setup otel and send to seq 2025-06-07 14:13:03 -05:00
7 changed files with 115 additions and 5 deletions
+16 -1
View File
@@ -44,8 +44,23 @@ jobs:
username: ${{ secrets.SSH_USERNAME }} username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_KEY }} key: ${{ secrets.SSH_KEY }}
script: | script: |
cd altgen
echo 'SeqOptions__ServerUrl=http://seq:80' >> .env
echo 'SeqOptions__ApiKeyHeader=X-Seq-ApiKey' >> .env
echo 'SeqOptions__ApiKey=${{ secrets.SEQ_API_KEY }}' >> .env
docker stop api.altgen.stevanfreeborn.com docker stop api.altgen.stevanfreeborn.com
docker rm api.altgen.stevanfreeborn.com docker rm api.altgen.stevanfreeborn.com
docker pull ${{ secrets.DOCKERHUB_USERNAME }}/api.altgen.stevanfreeborn.com:${{ needs.build.outputs.version }} docker pull ${{ secrets.DOCKERHUB_USERNAME }}/api.altgen.stevanfreeborn.com:${{ needs.build.outputs.version }}
docker run --restart always -d -p 7778:8080 --name api.altgen.stevanfreeborn.com ${{ secrets.DOCKERHUB_USERNAME }}/api.altgen.stevanfreeborn.com:${{ needs.build.outputs.version }} docker run \
--env-file .env \
--restart always \
-d \
-p 7778:8080 \
--name api.altgen.stevanfreeborn.com \
--network seq-network \
${{ secrets.DOCKERHUB_USERNAME }}/api.altgen.stevanfreeborn.com:${{ needs.build.outputs.version }}
rm .env
+5
View File
@@ -7,6 +7,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.1" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.1" />
</ItemGroup> </ItemGroup>
+21
View File
@@ -0,0 +1,21 @@
using System.Diagnostics;
namespace AltGen.API.Common;
class Instrumentation : IDisposable
{
internal const string ActivitySourceName = "AltGen.API";
internal const string ActivitySourceVersion = "1.0.0";
public Instrumentation()
{
ActivitySource = new ActivitySource(ActivitySourceName, ActivitySourceVersion);
}
public ActivitySource ActivitySource { get; }
public void Dispose()
{
ActivitySource.Dispose();
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace AltGen.API.Common;
internal sealed class SeqOptions
{
public string ServerUrl { get; set; } = string.Empty;
public string ApiKeyHeader { get; set; } = string.Empty;
public string ApiKey { get; set; } = string.Empty;
public bool IsEnabled => !string.IsNullOrWhiteSpace(ServerUrl) && !string.IsNullOrWhiteSpace(ApiKeyHeader) && !string.IsNullOrWhiteSpace(ApiKey);
public string LogEndpoint => $"{ServerUrl}/ingest/otlp/v1/logs";
public string TraceEndpoint => $"{ServerUrl}/ingest/otlp/v1/traces";
public string AuthHeader => $"{ApiKeyHeader}={ApiKey}";
}
@@ -0,0 +1,51 @@
namespace AltGen.API.Common;
static class WebAppBuilderExtensions
{
public static WebApplicationBuilder AddTelemetry(this WebApplicationBuilder builder)
{
var seq = new SeqOptions();
builder.Configuration.GetSection(nameof(SeqOptions)).Bind(seq);
if (seq.IsEnabled is false)
{
return builder;
}
builder.Services.AddSingleton<Instrumentation>();
builder.Services.AddOpenTelemetry()
.ConfigureResource(resource =>
{
resource.AddService(Instrumentation.ActivitySourceName, Instrumentation.ActivitySourceVersion);
resource.AddAttributes(new Dictionary<string, object>
{
["service.name"] = Instrumentation.ActivitySourceName,
["service.version"] = Instrumentation.ActivitySourceVersion,
["service.instance.id"] = Environment.MachineName,
["service.namespace"] = "stevesbot",
["service.environment"] = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "production",
});
})
.WithLogging(lb => lb.AddOtlpExporter(o =>
{
o.Protocol = OtlpExportProtocol.HttpProtobuf;
o.Endpoint = new Uri(seq.LogEndpoint);
o.Headers = seq.AuthHeader;
}))
.WithTracing(tb =>
{
tb.AddSource(Instrumentation.ActivitySourceName);
tb.AddAspNetCoreInstrumentation();
tb.AddHttpClientInstrumentation();
tb.AddOtlpExporter(o =>
{
o.Protocol = OtlpExportProtocol.HttpProtobuf;
o.Endpoint = new Uri(seq.TraceEndpoint);
o.Headers = seq.AuthHeader;
});
});
return builder;
}
}
+2 -3
View File
@@ -1,8 +1,7 @@
using System.Globalization;
using System.Threading.RateLimiting;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
builder.AddTelemetry();
builder.Services.AddProblemDetails(); builder.Services.AddProblemDetails();
builder.Services.AddOpenApi(); builder.Services.AddOpenApi();
+7
View File
@@ -1,9 +1,11 @@
global using System.ComponentModel.DataAnnotations; global using System.ComponentModel.DataAnnotations;
global using System.Diagnostics.CodeAnalysis; global using System.Diagnostics.CodeAnalysis;
global using System.Globalization;
global using System.Reflection; global using System.Reflection;
global using System.Text; global using System.Text;
global using System.Text.Json; global using System.Text.Json;
global using System.Text.Json.Serialization; global using System.Text.Json.Serialization;
global using System.Threading.RateLimiting;
global using AltGen.API.Common; global using AltGen.API.Common;
global using AltGen.API.Generate; global using AltGen.API.Generate;
@@ -11,3 +13,8 @@ global using AltGen.API.Generate.Providers;
global using AltGen.API.Generate.Providers.Gemini; global using AltGen.API.Generate.Providers.Gemini;
global using Microsoft.AspNetCore.Mvc; global using Microsoft.AspNetCore.Mvc;
global using OpenTelemetry.Exporter;
global using OpenTelemetry.Logs;
global using OpenTelemetry.Resources;
global using OpenTelemetry.Trace;