Das ist eine für den Ausdruck optimierte Ansicht des gesamten Kapitels inkl. Unterseiten.
Druckvorgang starten.
Zur Standardansicht zurückkehren.
Logging & Telemetrie
Wie die DataBridge Logs erzeugt, welche Telemetrie sie sendet und wie Sampling die Kosten steuert.
Die DataBridge steuert ihr Telemetrie-Volumen über zwei voneinander unabhängige
Mechanismen:
- Gepuffertes Logging — Log-Einträge werden pro Funktionsausführung gesammelt und
erst am Ende des Laufs, abhängig vom Ergebnis, selektiv gesendet.
- Sampling von Abhängigkeiten — ausgehende Aufrufe an Quell- und Zielsysteme werden
nur anteilig gesendet, sofern sie erfolgreich und schnell waren.
Der zweite Mechanismus ist der eigentliche Kostenhebel: In einer Volumenanalyse über
90 Tage entfielen rund 78 % des gesamten Datenvolumens auf Abhängigkeiten und nur ein
Bruchteil auf Log-Einträge.
| Seite | Inhalt |
|---|
| Metriken | Custom Metrics — die einzige nicht gesampelte Mengenangabe |
| Performance & Laufzeiten | KQL-Abfragen für Laufzeiten, Fehler, Abhängigkeiten und Datenvolumen |
Gepuffertes Logging — drei Lauf-Ergebnisse
| Ergebnis | Kriterium | Gesendete Log-Level |
|---|
| Normaler Lauf | Keine Fehler, keine Warnungen | Nur Warning + Error + ~20 % der Information-Einträge (konfigurierbar) |
| Lauf mit Warnungen | Mindestens eine Warning, kein Fehler | Alle Information + Warning + Error |
| Fehlerlauf | Mindestens ein unbehandelter Fehler | Alle Debug + Information + Warning + Error |
Der Anteil der Information-Einträge im Normalbetrieb wird über
TELEMETRY_INFO_SAMPLE_RATE gesteuert (Standard: 20 = 20 %). Die Stichprobe wird
pro Eintrag gezogen — es entstehen also vereinzelte Traces aus allen Läufen,
keine vollständigen Ketten. Lückenlose Ketten gibt es nur bei Warning- und Fehler-Läufen.
Trace-Level erreicht Application Insights nie
`LogTrace` ist ausschließlich live sichtbar
Log-Einträge auf Level Trace werden niemals an Application Insights gesendet —
auch nicht bei Fehler-Läufen. Der Telemetriepfad ist auf Debug und höher begrenzt.
Sichtbar sind sie nur live: lokal in der Konsole bzw. im Container-Log, in Azure im
Log Stream der Function App (oder per az webapp log tail).
Sampling von Abhängigkeiten
Ausgehende Aufrufe an Quell- und Zielsysteme (D365 OData, SQL, Table Storage, Service Bus)
werden von Application Insights automatisch als Dependencies erfasst. Ohne Filterung
verursachen sie bei kurzem Polling-Intervall ein Vielfaches aller Log-Einträge zusammen.
| Aufruf | Wird gesendet |
|---|
| Fehlgeschlagen | Immer vollständig |
Langsam (≥ TELEMETRY_DEPENDENCY_SLOW_MS) | Immer vollständig |
| Erfolgreich und schnell | Nur zum Anteil TELEMETRY_DEPENDENCY_SAMPLE_RATE (Standard 10 %) |
Die Entscheidung fällt pro Aufruf
Anders als beim Logging wird hier pro Aufruf entschieden, und zwar in dem Moment,
in dem der Aufruf endet — also bevor bekannt ist, ob die Funktionsausführung insgesamt
erfolgreich war.
Praktische Folge: Ein fehlgeschlagener Lauf enthält garantiert den fehlgeschlagenen
Aufruf, aber nicht zwangsläufig die erfolgreichen Aufrufe davor. Wird der vollständige
Verlauf für eine Analyse gebraucht, ist vorübergehend TELEMETRY_CONTROL=TRACE_ALL
zu setzen.
Steuerung über TELEMETRY_CONTROL
Die Einstellung wirkt auf beide Mechanismen — Traces und Abhängigkeiten:
| Wert | Wirkung |
|---|
TRACE_SAMPLE (Standard) | Selektives Sampling wie oben beschrieben |
TRACE_ALL | Sendet alles, deaktiviert jedes Sampling (für aktive Fehlersuche) |
TRACE_NONE | Unterdrückt Traces und Abhängigkeiten vollständig |
Eine leere Variable entspricht TRACE_SAMPLE. Details zu allen Telemetrie-Einstellungen
stehen unter Umgebungsvariablen.
`TRACE_ALL` nicht dauerhaft setzen
TRACE_ALL deaktiviert sämtliches Sampling und kann das Datenvolumen um ein Vielfaches
erhöhen — bis hin zum Erreichen der Tagesobergrenze (Daily Cap), ab der gar keine
Telemetrie mehr ankommt. Nur gezielt für die Dauer einer Analyse aktivieren.
Auswirkung auf bestehende Auswertungen
Bestehende Alerts und Dashboards prüfen
Verworfene Abhängigkeiten werden vollständig entfernt und nicht über einen
Hochrechnungsfaktor (itemCount) kompensiert.
Auswertungen über dependencies / AppDependencies, die auf absoluten Zählungen
oder Durchschnittslaufzeiten beruhen, liefern zu niedrige Werte.
Besonders kritisch sind Fehlerquoten der Form countif(success == false) / count():
Da fehlgeschlagene Aufrufe vollständig erhalten bleiben, erfolgreiche aber gesampelt
werden, ist das Ergebnis deutlich überhöht. Solche Abfragen und darauf basierende
Alerts sind zu entfernen oder auf die Tabelle requests umzustellen, die keinem
Sampling unterliegt.
Nicht betroffen sind:
- Fehleranzahlen und Fehlerursachen — fehlgeschlagene Aufrufe werden nie verworfen
- Auswertungen langsamer Aufrufe — ab dem Schwellwert immer vollständig
- Requests, Exceptions, Traces und Custom Metrics — unverändert
Wichtige Log-Felder in Application Insights
| Feld | Beschreibung |
|---|
operation_Id | Korrelations-ID — verknüpft alle Einträge einer einzigen Funktionsausführung |
operation_ParentId | Span-ID des Requests — sorgt für die korrekte Einordnung in der End-to-End-Transaktionsansicht |
operation_Name | Name der ausgeführten Function (z. B. GetChanges, ProcessStandardQueueItems) |
timestamp | Zeitpunkt des ursprünglichen Log-Aufrufs, nicht des Sendens am Ende der Ausführung |
message | Log-Text |
severityLevel | 0 = Verbose, 1 = Information, 2 = Warning, 3 = Error, 4 = Critical |
customDimensions.Category | .NET-Logger-Kategorie |
customDimensions.Exception | Vollständiger Stack Trace (nur bei Exceptions) |
Automatisch erfasste Telemetrie
Neben den eigenen Log-Einträgen erfasst Application Insights selbstständig:
- Requests — je Funktionsausführung, mit Laufzeit und Erfolgskennzeichen
- Exceptions — jede aufgetretene Ausnahme mit Stack Trace
- Dependencies — jeder ausgehende Aufruf (unterliegt dem Sampling, siehe oben)
Auswertung im Azure Portal
Application Insights → Untersuchen → Leistung
Zeigt alle Funktionsausführungen mit Durchschnittslaufzeit und P50/P95/P99-Perzentilen.
Ein hoher P95-Wert deutet auf gelegentliche Verzögerungen hin (langsames Zielsystem,
Queue-Stau).
Fehlerdiagnose — Failures Blade
Application Insights → Untersuchen → Fehler
Fehlgeschlagene Aufrufe, gruppiert nach Fehlertyp, mit direktem Zugriff auf Stack Traces.
Einzelne Ausführung verfolgen — Transaction Search
Application Insights → Untersuchen → Transaktionssuche
Filter nach operation_Id, um alle Einträge einer einzigen Ausführung zu sehen.
Tipps für die Fehlersuche
operation_Id finden: Im Failures Blade auf einen fehlgeschlagenen Request klicken →
End-to-End Transaction Details → operation_Id ist in der URL bzw. in den Details sichtbar.
Komplette Traces aktivieren: TELEMETRY_CONTROL = TRACE_ALL setzen, den
problematischen Job über ExecuteJob manuell auslösen, anschließend zurücksetzen.
Zwischen Funktionen korrelieren: Schlägt eine der Process…QueueItems-Funktionen
fehl, ist die operation_Id der ursprünglichen GetChanges-Ausführung in der Nachricht
gespeichert — so lässt sich der vollständige Pfad eines Datensatzes nachvollziehen.
Beachten Sie dabei die Einschränkung beim Dependency-Sampling (siehe oben).
1 - Metriken
Custom Metrics der DataBridge — vorab aggregiert und ohne Sampling.
Neben Traces und Requests sendet die dsyr.DataBridge eigene Custom Metrics an
Application Insights. Metriken sind numerische Zeitreihen mit Dimensionen — sie eignen
sich für Dashboards, Trend-Analysen und Metric Alerts, ohne dass dafür Log-Einträge
durchsucht werden müssen.
Die Metriken werden über TelemetryClient.GetMetric() vorab aggregiert: Das SDK
sammelt die Werte lokal in 1-Minuten-Intervallen und sendet pro Intervall und
Dimensionskombination einen aggregierten Datenpunkt (Summe, Anzahl, Min, Max).
Metriken unterliegen keinem Sampling
Weder das gepufferte Logging noch das Dependency-Sampling noch das
Application-Insights-Sampling wirken auf Custom Metrics. Für belastbare Mengenangaben
sind sie deshalb die einzige verlässliche Quelle.
Verfügbare Metriken
Alle Metriken verwenden den Namespace DataBridge.
| Metrik | Dimensionen | Quelle | Bedeutung |
|---|
ChangesDetected | JobName | GetChanges → ProcessJobsForRetrievalInOrderService | Anzahl der erkannten geänderten Datensätze pro Job und Lauf (kumuliert pro Lauf, inkl. 0) |
MessagesProcessed | JobName, Outcome (Success/Failed/Transitive) | ProcessStandardQueueItems/ProcessLowPriorityQueueItems/ProcessHighPriorityQueueItems → ProcessQueueMessageService | Eine verarbeitete Queue-Nachricht mit ihrem Ausgang. Queue-übergreifend: alle drei Prioritäts-Queues schreiben in dieselbe Metrik, unterscheidbar nur über den Ausgang, nicht über die Queue. Transitive heißt: die Nachricht wurde nicht endgültig verworfen, sondern in eine Retry-Queue umgeleitet. |
ProcessingDurationMs | JobName | ProcessStandardQueueItems/ProcessLowPriorityQueueItems/ProcessHighPriorityQueueItems → ProcessQueueMessageService | Verarbeitungsdauer einer einzelnen Queue-Nachricht in Millisekunden, unabhängig vom Ausgang. |
GetChanges hat keine job-genaue Erfolgs- oder Laufzeit-Metrik
Für GetChanges selbst gibt es aktuell nur ChangesDetected (Anzahl, kein
Erfolg/Fehler-Signal) auf Job-Ebene. Erfolgsquote und Laufzeit von GetChanges stammen
aus den automatisch von der Functions-Runtime erzeugten Host-Metriken
(GetChanges Successes/Failures/AvgDurationMs/…, siehe unten) — die kennen nur den
gesamten Timer-Lauf, nicht die einzelnen Jobs darin.
Null-Werte sind bedeutungstragend
Auch Läufe ohne erkannte Änderungen schreiben den Wert 0. Dadurch ist unterscheidbar,
ob ein Job gelaufen ist und nichts gefunden hat oder gar nicht gelaufen ist — eine
Lücke in der Serie bedeutet Letzteres. Das macht die Metrik zur besten Grundlage für
Alerts auf hängende Jobs.
Anzeige in Azure
Metrics Explorer
Application Insights → Metriken → Namespace DataBridge auswählen → Metrik
ChangesDetected. Als Aggregation eignet sich Summe (Anzahl Datensätze) oder
Anzahl (Anzahl Läufe).
Einmalige Freischaltung für Dimensionen
Um im Metrics Explorer nach der Dimension JobName zu filtern oder zu splitten, muss
einmalig pro Application-Insights-Ressource die Option „Enable alerting on custom metric
dimensions" aktiviert werden:
Application Insights → Usage and estimated costs → Custom metrics.
Ohne diese Option erscheint die Metrik nur als Gesamtaggregat über alle Jobs.
Die KQL-Abfrage funktioniert unabhängig davon.
KQL (Logs)
Jeder aggregierte Datenpunkt landet zusätzlich in der Tabelle customMetrics:
customMetrics
| where name == "ChangesDetected"
| extend job = tostring(customDimensions["JobName"])
| summarize sum(valueSum) by bin(timestamp, 2m), job
| render timechart
Host-generierte Metriken (Functions-Runtime)
Zusätzlich zu den oben aufgeführten, selbst erzeugten Metriken schreibt die
Azure-Functions-Runtime automatisch pro Funktion aggregierte Kennzahlen ebenfalls in
die Tabelle customMetrics — ohne dass die DataBridge dafür Code enthält:
<FunctionName> Successes
<FunctionName> Failures
<FunctionName> SuccessRate
<FunctionName> AvgDurationMs
<FunctionName> MinDurationMs
<FunctionName> MaxDurationMs
<FunctionName> ist z. B. GetChanges, ProcessStandardQueueItems,
ProcessLowPriorityQueueItems oder ProcessHighPriorityQueueItems. Diese Metriken sind
Standardverhalten des Functions-Hosts (WebJobs SDK Function Result Aggregator) und daher
in jeder Azure-Functions-App vorhanden, unabhängig von der DataBridge selbst. Das
Grafana-Dashboard nutzt sie für die Kopfzeilen-Tachos und die
Ausführungen/Laufzeiten-Panels der Zeile „GetChanges".
Nur Funktions-Ebene, keine Job-Ebene
Diese Host-Metriken kennen ausschließlich die aufrufende Funktion, nicht die einzelnen
Jobs, die innerhalb eines Laufs verarbeitet werden. Für job-genaue Aussagen sind
ChangesDetected bzw. MessagesProcessed/ProcessingDurationMs maßgeblich.
Limits
| Limit | Wert | Anmerkung |
|---|
| Dimensionen pro Metrik | 10 | Azure-Monitor-Limit |
| Zeitreihen pro Metrik (SDK-Default) | 1.000 | seriesCountLimit der SDK-Pre-Aggregation |
| Distinct-Werte pro Dimension (SDK-Default) | 100 | valuesPerDimensionLimit |
Konsequenz: Dimensionswerte müssen niedrig-kardinal sein — Job-Namen, Queue-Namen
und Status-Codes sind geeignet; IDs, Zeitstempel oder Datensatz-Schlüssel nicht.
2 - Performance & Laufzeiten
KQL-Abfragen für Laufzeiten, Fehlerquoten, Abhängigkeiten und Datenvolumen.
Die folgenden Abfragen können direkt im Logs-Bereich von Application Insights
(Kusto Query Language) ausgeführt werden.
Laufzeiten und Fehler
Laufzeiten aller Funktionen (letzte 24 Stunden)
requests
| where timestamp > ago(24h)
| summarize
Aufrufe = count(),
DurchschnittMs = avg(duration),
P95Ms = percentile(duration, 95),
Fehler = countif(success == false)
by name
| order by DurchschnittMs desc
Verlauf einer einzelnen Funktion (letzte 7 Tage)
requests
| where timestamp > ago(7d)
| where name == "GetChanges"
| summarize
P50Ms = percentile(duration, 50),
P95Ms = percentile(duration, 95),
Fehler = countif(success == false),
Läufe = count()
by bin(timestamp, 1h)
| order by timestamp asc
Durchschnittliche Laufzeit der letzten 30 Tage (täglich)
requests
| where timestamp > ago(30d)
| summarize
DurchschnittMs = avg(duration),
P95Ms = percentile(duration, 95)
by name, bin(timestamp, 1d)
| order by name asc, timestamp asc
Fehlerquote je Funktion (letzte 7 Tage)
requests
| where timestamp > ago(7d)
| summarize
Gesamt = count(),
Fehler = countif(success == false),
FehlerPct = round(100.0 * countif(success == false) / count(), 1)
by name
| order by FehlerPct desc
Warnungen und Fehler im Zeitverlauf
traces
| where timestamp > ago(7d)
| where severityLevel >= 2 // 2 = Warning, 3 = Error
| summarize Anzahl = count() by severityLevel, bin(timestamp, 1h), operation_Name
| order by timestamp asc
Top-10 häufigste Fehlermeldungen
exceptions
| where timestamp > ago(7d)
| summarize Anzahl = count() by outerMessage
| top 10 by Anzahl desc
Einzelne Ausführung nachvollziehen
Alle Einträge einer Ausführung (per operation_Id)
union requests, traces, exceptions
| where operation_Id == "<operation_Id hier einfügen>"
| project timestamp, itemType, severityLevel, message, outerMessage, operation_Name
| order by timestamp asc
Fehlerläufe mit allen zugehörigen Traces (letzte 24 Stunden)
let fehlgeschlagene =
requests
| where timestamp > ago(24h)
| where success == false
| project operation_Id, FunktionsName = name, Startzeit = timestamp;
traces
| where timestamp > ago(24h)
| join kind=inner fehlgeschlagene on operation_Id
| project Startzeit, FunktionsName, severityLevel, message
| order by Startzeit desc, severityLevel desc
Abhängigkeiten
Langsamste Abhängigkeiten (letzte 24 Stunden)
Zeigt die ausgehenden Aufrufe an Quell- und Zielsysteme mit den höchsten Laufzeiten:
dependencies
| where timestamp > ago(24h)
| summarize
Aufrufe = count(),
DurchschnittMs = avg(duration),
P95Ms = percentile(duration, 95),
Fehler = countif(success == false)
by type, target, name
| order by P95Ms desc
| take 20
Hinweis
Erfolgreiche, schnelle Aufrufe werden gesampelt (siehe
Sampling von Abhängigkeiten). Die Spalte Aufrufe ist
deshalb keine vollständige Zählung. Langsame und fehlgeschlagene Aufrufe sind dagegen
vollständig enthalten — für genau diese Auswertung ist die Abfrage also aussagekräftig.
Fehlgeschlagene Abhängigkeiten nach Zielsystem (letzte 7 Tage)
dependencies
| where timestamp > ago(7d)
| where success == false
| summarize Fehler = count() by type, target, resultCode
| order by Fehler desc
Datenvolumen und Kosten
Datenvolumen pro Tabelle
Wenn das tägliche Datenvolumen die konfigurierte Obergrenze (Daily Cap) erreicht, zeigt
diese Abfrage, welche Tabelle den Verbrauch verursacht:
union withsource = Tabelle *
| where TimeGenerated > ago(7d)
| summarize VolumenMB = round(sum(_BilledSize) / 1024.0 / 1024.0, 1) by Tabelle, bin(TimeGenerated, 1d)
| order by TimeGenerated desc, VolumenMB desc
Hinweis
Erfahrungsgemäß dominiert AppDependencies das Volumen deutlich. Greift die Obergrenze
trotz aktivem Sampling, ist TELEMETRY_DEPENDENCY_SAMPLE_RATE weiter zu reduzieren.
Zusätzlich ist zu prüfen, ob TELEMETRY_CONTROL versehentlich auf TRACE_ALL steht —
damit ist jedes Sampling deaktiviert.
Hinweise zur Interpretation
Warum fehlen manche Traces bei erfolgreichen Läufen?
Das Buffering sendet bei erfolgreichen Läufen nur einen Teil der Information-Einträge
und keine Debug-Einträge. Die Stichprobe wird pro Eintrag gezogen: Jede einzelne
Information-Zeile hat unabhängig eine Chance von 20 % (konfigurierbar via
TELEMETRY_INFO_SAMPLE_RATE), gesendet zu werden. Das führt zu einem gleichmäßigen Strom
vereinzelter Traces — vollständige, lückenlose Ketten gibt es nur bei Warning- und
Fehler-Läufen.
Trace-Einträge erreichen Application Insights grundsätzlich nie — sie sind nur live in
der Konsole bzw. im Log Stream sichtbar.
Warum fehlen manche Abhängigkeiten?
Fehlgeschlagene und langsame Aufrufe kommen immer vollständig an, erfolgreiche und
schnelle nur zu einem Anteil von 10 % (konfigurierbar via
TELEMETRY_DEPENDENCY_SAMPLE_RATE).
Anders als bei den Log-Einträgen wird diese Entscheidung pro Aufruf getroffen — in dem
Moment, in dem der Aufruf endet, also bevor das Ergebnis der Ausführung bekannt ist.
In der End-to-End-Transaktionsansicht sind daher auch bei einem fehlgeschlagenen Lauf
nicht zwangsläufig alle ausgehenden Aufrufe zu sehen. Für eine lückenlose Kette ist
temporär TELEMETRY_CONTROL=TRACE_ALL zu setzen.
Requests vs. Traces vs. Dependencies
| Telemetrie-Typ | Wird immer erfasst? | Enthält Laufzeit? |
|---|
| Request | Ja — jede Invocation | Ja |
| Exception | Ja — jede Exception | Nein |
| Trace | Nein — abhängig vom Outcome | Nein |
| Dependency | Nein — garantiert nur, wenn der Aufruf selbst fehlschlägt oder den Langsam-Schwellwert überschreitet | Ja |
| Custom Metric | Ja — vorab aggregiert, kein Sampling | Nein |
Für Laufzeit-Analysen der Funktionen immer die requests-Tabelle verwenden, für Laufzeiten
einzelner Fremdsystem-Aufrufe die dependencies-Tabelle, für inhaltliche Diagnose die
traces-Tabelle. Für belastbare Mengenangaben ausschließlich die
Custom Metrics, da diese nicht gesampelt werden.
Korrelation über operation_Id
Jede Funktionsausführung erhält eine eindeutige operation_Id. Alle Traces, Requests und
Exceptions dieser Invocation tragen dieselbe ID. Das erlaubt es, in KQL alle
zusammengehörenden Einträge mit einem einzigen Filter zu finden.