kubectl describe trainer fpommerening
{
name: "Frank Pommerening",
employer: {},
skills: [
"Senior-Softwareentwickler",
"Consultant",
"Trainer"
],
communication:{
email : "frank@pommerening-consulting.de",
twitter: "@fpommerening"
}
}
C++ | .NET | Erlang/Elixir | GO |
Java | JavaScript | PHP | Python |
Ruby | Rust | Swift |
ASP.NET | ASP.NET Core | HTTP clients |
Grpc.Net.Client | Redis Client | MS SQL Client |
services.AddOpenTelemetry().ConfigureResource(rb => rb.AddEnvironmentVariableDetector().AddService(ServiceName)) .WithMetrics(metricsBuilder => { metricsBuilder.AddAspNetCoreInstrumentation(); metricsBuilder.AddHttpClientInstrumentation(); metricsBuilder.AddOtlpExporter(otlpOptions =>{ otlpOptions.Endpoint = new Uri(...);})); }) .WithTracing(WithTracing => { traceBuilder.SetSampler(new AlwaysOnSampler()); traceBuilder.AddAspNetCoreInstrumentation(); traceBuilder.AddHttpClientInstrumentation(); traceBuilder.AddOtlpExporter(otlpOptions =>{ otlpOptions.Endpoint = new Uri(...);})); });
using var tracerProvider = Sdk.CreateTracerProviderBuilder() .ConfigureResource(res => res.AddService(ServiceName)) .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddOtlpExporter(otlpOptions =>{ otlpOptions.Endpoint = new Uri(...); .Build();
using var meterProvider = Sdk.CreateMeterProviderBuilder() .ConfigureResource(res => res.AddService(ServiceName)) .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddOtlpExporter(otlpOptions =>{ otlpOptions.Endpoint = new Uri(...); .Build();
ActivitySource ActivitySource = new ActivitySource(ActivitySourceName, ...)
using var activity = ActivitySource.StartActivity(ActivityName);
Meter Meter = new Meter(MeterName, ...)
var counter = Meter.CreateCounter<int>(CounterName, Unit, Description);
var gauge = Meter.CreateObservableGauge<int>(CounterName, ()=>GetValue(), Unit, Description);
receivers: otlp: protocols: grpc:{} http:{} exporters: jaeger: endpoint: jaeger.fqdn:14250 extensions: health_check: {} processors: batch: {} service: extensions: - health_check pipelines: traces: exporters: - jaeger processors: - batch receivers: - otlp
receivers: otlp: protocols: grpc:{} http:{} exporters: jaeger: endpoint: jaeger.fqdn:14250 extensions: health_check: {} processors: batch: {} service: extensions: - health_check pipelines: traces: exporters: - jaeger processors: - batch receivers: - otlp
receivers: otlp: protocols: grpc:{} http:{} exporters: jaeger: endpoint: jaeger.fqdn:14250 extensions: health_check: {} processors: batch: {} service: extensions: - health_check pipelines: traces: exporters: - jaeger processors: - batch receivers: - otlp
receivers: otlp: protocols: grpc:{} http:{} exporters: jaeger: endpoint: jaeger.fqdn:14250 extensions: health_check: {} processors: batch: {} service: extensions: - health_check pipelines: traces: exporters: - jaeger processors: - batch receivers: - otlp
receivers: otlp: protocols: grpc:{} http:{} exporters: jaeger: endpoint: jaeger.fqdn:14250 extensions: health_check: {} processors: batch: {} service: extensions: - health_check pipelines: traces: exporters: - jaeger processors: - batch receivers: - otlp
receivers: otlp: protocols: grpc:{} http:{} exporters: jaeger: endpoint: jaeger.fqdn:14250 extensions: health_check: {} processors: batch: {} service: extensions: - health_check pipelines: traces: exporters: - jaeger processors: - batch receivers: - otlp
receivers: otlp: protocols: grpc:{} http:{} exporters: jaeger: endpoint: jaeger.fqdn:14250 extensions: health_check: {} processors: batch: {} service: extensions: - health_check pipelines: traces: exporters: - jaeger processors: - batch receivers: - otlp
receivers: otlp: protocols: grpc:{} http:{} exporters: jaeger: endpoint: jaeger.fqdn:14250 extensions: health_check: {} processors: batch: {} service: extensions: - health_check pipelines: traces: exporters: - jaeger processors: - batch receivers: - otlp
receivers: otlp: protocols: grpc:{} http:{} exporters: jaeger: endpoint: jaeger.fqdn:14250 extensions: health_check: {} processors: batch: {} service: extensions: - health_check pipelines: traces: exporters: - jaeger processors: - batch receivers: - otlp
receivers: otlp: protocols: grpc:{} http:{} exporters: jaeger: endpoint: jaeger.fqdn:14250 extensions: health_check: {} processors: batch: {} service: extensions: - health_check pipelines: traces: exporters: - jaeger processors: - batch receivers: - otlp
receivers: otlp: protocols: grpc:{} http:{} exporters: jaeger: endpoint: jaeger.fqdn:14250 extensions: health_check: {} processors: batch: {} service: extensions: - health_check pipelines: traces: exporters: - jaeger processors: - batch receivers: - otlp
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
receivers: otlp: protocols: grpc: {} processors: resource: attributes: - action: insert key: loki.resource.labels value: service.name exporters: otlp/jeager: endpoint: jaeger-collector.jaeger:4317 tls: insecure: true prometheus: endpoint: "${MY_POD_IP}:9090" send_timestamps: true metric_expiration: 15m resource_to_telemetry_conversion: enabled: true loki: endpoint: http://loki-write.loki:3100/loki/api/v1/push otlp/aspecto: endpoint: otelcol.aspecto.io:4317 headers: Authorization: not-my-key service: pipelines: logs: receivers: - otlp processors: - resource exporters: - loki metrics: receivers: - otlp exporters: - prometheus traces: receivers: - otlp exporters: - otlp/jeager - otlp/aspecto
Lokale Anwendungen GitHub Services.AddOpenTelemetry()
.WithMetrics(mb => mb.AddOtlpExporter(opt => opt.Endpoint = new Uri(...)));
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry().WithMetrics(mb => mb.AddPrometheusExporter());
var app = builder.Build();
app.UseOpenTelemetryPrometheusScrapingEndpoint();
var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter(MyMeter.Name)
.AddPrometheusHttpListener(options => options.UriPrefixes =
new string[] { "http://localhost:9090/" })
.Build();
public const string MeterName = "fp.monitoring.workshop.instrumentationlibrary";
using Meter meter = new Meter(MeterName);
Services.AddOpenTelemetry().WithMetrics(mb => mb.AddMeter(MeterName));
Counter<int> executionCounter = meter.CreateCounter<int>("executions");
executionCounter.Add(1);
Vergleichbar mit der Counter-Metrik, hält die ObservableCounter-Metrik den State (Wert) nicht selbst, sondern erhält ihn über eine Funktion.ObservableCounter<int> executionCounter =
meter.CreateCounter<int>("executions", ()=> QueryExecutions());
UpDownCounter-Metriken sind mit den Counter-Metriken vergleich. Abweichend sind Inkrementierung und Dekrementierung vorgesehen.
Beispiel: Länge einer Warteschlange
UpDownCounter<int> queryItemCounter = meter.CreateUpDownCounter<int>("query.lenght");
queryItemCounter.Add(5);
queryItemCounter.Add(-1);
Die ObservableUpDownCounter-Metriken unterstützen ObservableUpDownCounter<int> queryLength =
meter.CreateObservableUpDownCounter<int>("query.lenght", ()=> MyQuery.Lenght);
Einige Exporter haben keine native Unterstützung für UpDownCounter-Metriken. Sie werden dann meist als Gauge-Metrik exportiert.Gauge-Metriken können beliebige Zahlenwerte annehmen. Die Ermittlung des aktuellen Wertes erfolgt bei der Veröffentlichung der Metriken.
Je nach Aufwand ist ein Cache zu empfehlen.
Beispiele: aktueller RAM-Verbrauch, Anzahl Objekte im Lager.
meter.CreateObservableGauge("my_sample_gauge", observeValue: () => ObserveMyValue());
Histogram-Metriken stellen die Verteilung von Zahlenwerten in Buckets dar.
Beispiel: Verarbeitungszeit je Anfrage.
Histogram<double> mySampleHistogram = meter.CreateHistogram<double>("my_sample_histogram");
mySampleHistogram.Record(14.5d);
mySampleHistogram.Record(67.1d);
OpenTelemetry liefert einen Default für die Bucketgrenzen der Histogramme. Eigene Werte können ggf. in diesen Grenzen unzureichend abgebildet werden. Die Konfiguration eines View definiert eigene Bucket-Boundaries.
Services.AddOpenTelemetry().WithMetrics(mb =>{ ...
mb.AddView("my_sample_histogram",
new ExplicitBucketHistogramConfiguration
{
Boundaries = new double[] {1, 2, 5, 10, 50, 100}
});
});
Einheiten (Units) und Beschreibung (Descriptions) sind optionale Metadaten. Diese werden bei der Erstellung der Metriken angegeben.
UpDownCounter<int> queryLength =
meter.CreateUpDownCounter<int>("query.lenght","wi", "count of unprocessed work items");
meter.CreateObservableGauge("system.ram.free",
()=>> querySystemRam(), "MiB", "amount of free system memory");
Labels sind optionale Metadaten, die den jeweiligen Metrik-Wert näher beschreiben. Die Angabe erfolgt als 1 .. n Key-Value-Pair.
MyIntSampleCounter.Add(2, KeyValuePair.Create<string, object>("label1", value)); MySampleHistogram.Record(14.5d, new TagList{{"label1", 42}}); meter.CreateObservableGauge("my.sample.gauge", observeValue: () => new Measurement<int>(42, KeyValuePair.Create<string, object>("label2", "value2")));
MyIntSampleCounter.Add(2, KeyValuePair.Create<string, object>("label1", value)); MySampleHistogram.Record(14.5d, new TagList{{"label1", 42}}); meter.CreateObservableGauge("my.sample.gauge", observeValue: () => new Measurement<int>(42, KeyValuePair.Create<string, object>("label2", "value2")));
MyIntSampleCounter.Add(2, KeyValuePair.Create<string, object>("label1", value)); MySampleHistogram.Record(14.5d, new TagList{{"label1", 42}}); meter.CreateObservableGauge("my.sample.gauge", observeValue: () => new Measurement<int>(42, KeyValuePair.Create<string, object>("label2", "value2")));
MyIntSampleCounter.Add(2, KeyValuePair.Create<string, object>("label1", value)); MySampleHistogram.Record(14.5d, new TagList{{"label1", 42}}); meter.CreateObservableGauge("my.sample.gauge", observeValue: () => new Measurement<int>(42, KeyValuePair.Create<string, object>("label2", "value2")));
Services.AddOpenTelemetry()
.WithTracing(tb =>
{
tb.SetSampler(SAMPLER);
tb.AddOtlpExporter(opt => opt.Endpoint = new Uri(...));
});
Services.AddOpenTelemetry()
.WithTracing(tb =>
{
...
tb.AddAspNetCoreInstrumentation();
tb.AddHttpClientInstrumentation();
tb.AddGrpcClientInstrumentation();
...
});
public const string ActivitySourceName = "fp.monitoring.workshop.instrumentationlibrary";
using myActivitySource = new ActivitySource(ActivitySourceName);
Der Name ist wichtig für die Registrierung bei OpenTelemetry.Services.AddOpenTelemetry()
.WithTracing(tb =>
{ tb.AddSource(ActivitySourceName); });
using var activity = ActivitySource.StartActivity(ActivityName);
Die Methode CreateActivity erstellt eine neue Aktivität. Sie überschreibt nicht Activity.Current. In der Praxis spielt diese Funktion meist keine Rolle. Activity.Current?.SetTag("myKey", myValue)
var value = Activity.Current?.GetTagItem("myKey");
Activity.Current?.SetStatus(ActivityStatusCode.Ok);
var status = Activity.Current?.GetStatus()
var activityEvent = new ActivityEvent("Something is happen...");
Activity.Current?.AddEvent(activityEvent);
Activity.Current?.RecordException(EXCEPTION);
var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddOpenTelemetry(options =>
{
options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(ServiceName));
otlpOptions.Endpoint = new Uri(...);
}
Die ASP.NET Core Umgebung gibt standardmäßig Logs auf die Konsole aus. public class MyClass()
{
private ILogger<MyClass> _logger;
public MyClass(ILogger<MyClass> logger)
{
_logger = logger;
}
public void DoSomething()
{
_logger.LogInformation("INFO");
}
}