1.Serilog mit dem OpenTelemetry-Sink
Program.cs
// dotnet add package Serilog.AspNetCore
// dotnet add package Serilog.Sinks.OpenTelemetry
using Serilog;
using Serilog.Sinks.OpenTelemetry;
builder.Host.UseSerilog((ctx, lc) => lc
.ReadFrom.Configuration(ctx.Configuration)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.OpenTelemetry(o =>
{
o.Endpoint = "https://logs.uptimeeye.com/v1/ingest/otlp/v1/logs";
o.Protocol = OtlpProtocol.HttpProtobuf;
o.Headers = new Dictionary<string, string>
{
["Authorization"] = $"Bearer {Environment.GetEnvironmentVariable("UPTIMEEYE_INGEST_KEY")}",
["VL-Stream-Fields"] = "service.name,deployment.environment",
};
o.ResourceAttributes = new Dictionary<string, object>
{
["service.name"] = "checkout",
["deployment.environment"] = "prod",
};
}));
// later
Log.Information("payment authorized for {OrderId} in {DurationMs} ms", "4711", 812);Note: Template-Properties (
OrderId, DurationMs) werden zu Attributen und damit zu Feldern; die gerenderte Nachricht ist der Body des Logs.2.Microsoft.Extensions.Logging mit dem OpenTelemetry SDK
Program.cs
// dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
using OpenTelemetry.Logs;
using OpenTelemetry.Resources;
using OpenTelemetry.Exporter;
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.SetResourceBuilder(ResourceBuilder.CreateDefault()
.AddService("checkout")
.AddAttributes(new[] { new KeyValuePair<string, object>("deployment.environment", "prod") }));
logging.AddOtlpExporter(o =>
{
o.Endpoint = new Uri("https://logs.uptimeeye.com/v1/ingest/otlp/v1/logs");
o.Protocol = OtlpExportProtocol.HttpProtobuf;
o.Headers = $"Authorization=Bearer {Environment.GetEnvironmentVariable("UPTIMEEYE_INGEST_KEY")}";
});
});3.Container: JSON auf der Konsole
Lass den Agent der Plattform den Versand übernehmen. AddJsonConsole schreibt ein JSON-Objekt pro Zeile; Message ist die Nachricht und Timestamp die Zeit.
Program.cs
builder.Logging.ClearProviders();
builder.Logging.AddJsonConsole(o =>
{
o.IncludeScopes = true;
o.TimestampFormat = "yyyy-MM-dd'T'HH:mm:ss.fffZ";
o.UseUtcTimestamp = true;
});
// agent side: _msg_field=Message&_time_field=TimestampFelder, die du bekommst
Diese Felder erscheinen im Panel „Felder“ und funktionieren in jedem Filter:
service.name,deployment.environmentseverity_text- Properties der Message-Templates (
OrderId,DurationMs) Category/ Logger-Name- Exception-Details
Tipps
- Nimm Message-Templates (
{OrderId}), nie String-Interpolation – nur Templates erzeugen Felder. - Ergänz
Enrich.WithProperty("env", "prod"), wenn du neben dem Resource-Attribut ein schlichtes Feldenvwillst.
FAQ
Funktioniert Serilog.Sinks.Http auch?
Ja, mit einem eigenen
IHttpClient, der den Header Authorization setzt, und requestUri auf /v1/ingest/jsonline?_msg_field=RenderedMessage&_time_field=Timestamp. Der OpenTelemetry-Sink braucht keinen eigenen Code und ist deshalb der empfohlene Weg.Wo bekomme ich den Ingest-Key?
In der App unter API-Keys → Neuer API-Key → Typ „Log-Ingest“. Der Key beginnt mit
ue_ingest_ und wird nur einmal angezeigt. Management-Keys (ue_live_) lehnt der Ingest-Endpoint ab.Wie sehe ich, ob Logs ankommen?
Öffne Logs in der App, wähl den Zeitraum „15 Min.“ und such nach
service:=<your service>. Neue Zeilen sind nach etwa einer Sekunde durchsuchbar; Live-Tail zeigt sie mit etwa 6 s Verzögerung.Verwandte Seiten
OpenTelemetryRichte einen OpenTelemetry Collector oder ein beliebiges OTel-SDK per OTLP/HTTP auf UptimeEye Logs.HTTP API / curlDie Ingest-API von UptimeEye Logs: JSON-Lines per curl oder eigenem Code senden, Stream-Felder wählen, mit gzip komprimieren und Antwortcodes verstehen..DockerSchick die Logs aller Container eines Docker-Hosts an UptimeEye Logs: ein Vector-Container am Docker-Socket oder der Loki-Logging-Driver pro Container..Logs durchsuchenJetzt, wo Zeilen ankommen: Filter, Felder, Zeiträume und Live-Tail.