diff --git a/.github/workflows/deploy_api.yml b/.github/workflows/deploy_api.yml index f4c33d3..3153027 100644 --- a/.github/workflows/deploy_api.yml +++ b/.github/workflows/deploy_api.yml @@ -44,8 +44,23 @@ jobs: username: ${{ secrets.SSH_USERNAME }} key: ${{ secrets.SSH_KEY }} 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 rm api.altgen.stevanfreeborn.com 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 diff --git a/src/AltGen.API/AltGen.API.csproj b/src/AltGen.API/AltGen.API.csproj index 3aabe5f..9eeabf2 100644 --- a/src/AltGen.API/AltGen.API.csproj +++ b/src/AltGen.API/AltGen.API.csproj @@ -7,6 +7,11 @@ + + + + + diff --git a/src/AltGen.API/Common/Instrumentation.cs b/src/AltGen.API/Common/Instrumentation.cs new file mode 100644 index 0000000..16fd5b0 --- /dev/null +++ b/src/AltGen.API/Common/Instrumentation.cs @@ -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(); + } +} \ No newline at end of file diff --git a/src/AltGen.API/Common/SeqOptions.cs b/src/AltGen.API/Common/SeqOptions.cs new file mode 100644 index 0000000..9c7934a --- /dev/null +++ b/src/AltGen.API/Common/SeqOptions.cs @@ -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}"; +} \ No newline at end of file diff --git a/src/AltGen.API/Common/WebAppBuilderExtensions.cs b/src/AltGen.API/Common/WebAppBuilderExtensions.cs new file mode 100644 index 0000000..d215dd3 --- /dev/null +++ b/src/AltGen.API/Common/WebAppBuilderExtensions.cs @@ -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(); + + builder.Services.AddOpenTelemetry() + .ConfigureResource(resource => + { + resource.AddService(Instrumentation.ActivitySourceName, Instrumentation.ActivitySourceVersion); + resource.AddAttributes(new Dictionary + { + ["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; + } +} \ No newline at end of file diff --git a/src/AltGen.API/Program.cs b/src/AltGen.API/Program.cs index 6caf5b4..03d9ac1 100644 --- a/src/AltGen.API/Program.cs +++ b/src/AltGen.API/Program.cs @@ -1,8 +1,7 @@ -using System.Globalization; -using System.Threading.RateLimiting; - var builder = WebApplication.CreateBuilder(args); +builder.AddTelemetry(); + builder.Services.AddProblemDetails(); builder.Services.AddOpenApi(); diff --git a/src/AltGen.API/Usings.cs b/src/AltGen.API/Usings.cs index 8254e07..c21965a 100644 --- a/src/AltGen.API/Usings.cs +++ b/src/AltGen.API/Usings.cs @@ -1,13 +1,20 @@ global using System.ComponentModel.DataAnnotations; global using System.Diagnostics.CodeAnalysis; +global using System.Globalization; global using System.Reflection; global using System.Text; global using System.Text.Json; global using System.Text.Json.Serialization; +global using System.Threading.RateLimiting; global using AltGen.API.Common; global using AltGen.API.Generate; global using AltGen.API.Generate.Providers; global using AltGen.API.Generate.Providers.Gemini; -global using Microsoft.AspNetCore.Mvc; \ No newline at end of file +global using Microsoft.AspNetCore.Mvc; + +global using OpenTelemetry.Exporter; +global using OpenTelemetry.Logs; +global using OpenTelemetry.Resources; +global using OpenTelemetry.Trace; \ No newline at end of file