Expand BizTalk operational metrics
This commit is contained in:
+95
-40
@@ -12,7 +12,7 @@ Verbindliche Randbedingungen:
|
||||
|
||||
- Der Checkmk Windows Agent bleibt `LocalSystem`.
|
||||
- `LocalSystem` erhaelt keine BizTalk-/SQL-Gruppenmitgliedschaft.
|
||||
- Ein separates Dienstkonto oder bevorzugt gMSA sammelt minuetlich.
|
||||
- Ein normales dediziertes AD-Servicekonto sammelt minuetlich.
|
||||
- Der Agentpfad fuehrt niemals WMI- oder SQL-Abfragen aus.
|
||||
- Fehler muessen als gueltige Checkmk-`UNKNOWN`-Services sichtbar werden.
|
||||
- Schreiben und Lesen duerfen nie einen halben Snapshot exponieren.
|
||||
@@ -46,7 +46,7 @@ Konto.
|
||||
Privilegierte Zone
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Task Scheduler: "BizTalk Checkmk Pulse Provider" │
|
||||
│ Konto: DOMAIN\svc_biztalk_cmk$ (gMSA empfohlen) │
|
||||
│ Konto: DOMAIN\svc_biztalk_cmk (RunLevel Limited) │
|
||||
│ Intervall: 1 Minute, IgnoreNew, Laufzeitlimit 5 Minuten │
|
||||
│ │
|
||||
│ BizTalkCheckmkPulse.exe --collect │
|
||||
@@ -89,7 +89,7 @@ Ablauf:
|
||||
2. Tageslogs gemaess `LogRetentionDays` bereinigen.
|
||||
3. exklusives Handle auf `<SnapshotPath>.provider.lock` halten.
|
||||
4. WMI-, SQL- und Event-Log-Probes ausfuehren.
|
||||
5. sechs stabile und optionale dynamische Checkmk-Zeilen formatieren.
|
||||
5. acht stabile und optionale dynamische Checkmk-Zeilen formatieren.
|
||||
6. Snapshot in einer eindeutigen Temporaerdatei desselben Verzeichnisses
|
||||
schreiben.
|
||||
7. `Flush(true)` ausfuehren und Temporaerdatei atomar publizieren.
|
||||
@@ -132,19 +132,19 @@ Der Consumer:
|
||||
- gibt bei Erfolg ausschliesslich den validierten Payload aus.
|
||||
|
||||
Er gibt immer Exitcode `0` zurueck, damit ein Fehler die komplette
|
||||
Checkmk-Agentsektion nicht zerstoert. Jede Ablehnung erzeugt sechs
|
||||
Checkmk-Agentsektion nicht zerstoert. Jede Ablehnung erzeugt acht
|
||||
`UNKNOWN`-Zeilen und einen Eintrag im Consumer-Log.
|
||||
|
||||
## 4. Snapshot-Vertrag
|
||||
|
||||
Version 1:
|
||||
Version 2:
|
||||
|
||||
```text
|
||||
BIZTALK_CHECKMK_PULSE_SNAPSHOT_V1
|
||||
BIZTALK_CHECKMK_PULSE_SNAPSHOT_V2
|
||||
generatedUtc=2026-07-30T12:34:56.1234567Z
|
||||
machineBase64=QVYyM0FHUFdCSU8x
|
||||
identityBase64=QkVXXHN2Y19iaXp0YWxrX2NtayQ=
|
||||
payloadLines=6
|
||||
payloadLines=8
|
||||
payloadSha256=<64 hex characters>
|
||||
|
||||
0 "BizTalk Platform" - ...
|
||||
@@ -202,7 +202,37 @@ Pflichtklassen:
|
||||
Hostnamen werden clientseitig verglichen. Sonderzeichen und FQDN-/Kurzname
|
||||
gelangen nicht in dynamisch erzeugte WQL-Filter.
|
||||
|
||||
### 5.2 SQL-Zugriffsprobe
|
||||
`MSBTS_ServiceInstance` wird fuer `ServiceStatus=4` (resumable),
|
||||
`ServiceStatus=32` (non-resumable) und `ServiceClass=64` abgefragt.
|
||||
`ServiceClass=64` kennzeichnet Routing Failure Reports. Sie werden als eigene
|
||||
Metrik ausgewiesen und zugleich in `suspended_nonresumable` mitgezaehlt.
|
||||
|
||||
### 5.2 Kompaktes Checkmk-Servicebild
|
||||
|
||||
Die alte Sammelzeile `BizTalk Runtime Artifacts` wurde durch drei kurze
|
||||
Services ersetzt. Insgesamt entstehen acht stabile Services:
|
||||
|
||||
1. `BizTalk Platform`
|
||||
2. `BizTalk SQL Access`
|
||||
3. `BizTalk Suspended Instances`
|
||||
4. `BizTalk Host Instances`
|
||||
5. `BizTalk Receive Locations`
|
||||
6. `BizTalk Send Ports`
|
||||
7. `BizTalk Orchestrations`
|
||||
8. `BizTalk Event Log`
|
||||
|
||||
Receive Locations und Send Ports alarmieren nur fuer unerwartete
|
||||
Aus-Zustaende. Fachlich bewusst deaktivierte Namen werden exakt, ohne
|
||||
Wildcards, in `ExpectedDisabledReceiveLocations` beziehungsweise
|
||||
`ExpectedInactiveSendPorts` hinterlegt. Ein Eintrag ist entweder nur der Name
|
||||
oder `Anwendung\Name`.
|
||||
|
||||
Pro Summary werden maximal `MaxSummaryItems` Treffer angezeigt. Weitere
|
||||
Artefakte werden als `(+n more)` zusammengefasst. `MaxDetailCharacters`
|
||||
begrenzt jede Detailausgabe, damit Checkmk-Ansichten kompakt bleiben, waehrend
|
||||
alle numerischen Metriken vollstaendig erhalten bleiben.
|
||||
|
||||
### 5.3 SQL-Zugriffsprobe
|
||||
|
||||
Der Provider oeffnet fuer Management- und Master-MessageBox-Datenbank eine
|
||||
kurze `System.Data.SqlClient`-Verbindung mit integrierter
|
||||
@@ -213,7 +243,7 @@ Die Ausgabe `execution_identity=` zeigt deshalb das Provider-Konto, nicht mehr
|
||||
`NT AUTHORITY\SYSTEM`. Der Check beweist, dass genau das Scheduled-Task-Konto
|
||||
die Ziele erreichen kann.
|
||||
|
||||
### 5.3 Event Log
|
||||
### 5.4 Event Log
|
||||
|
||||
Der Provider liest das lokale Application Log im konfigurierten Zeitfenster
|
||||
und filtert Quellen wie `BizTalk Server`, `XLANG/s`, `ENTSSO`,
|
||||
@@ -286,14 +316,17 @@ Sollkonfiguration:
|
||||
| Programm | `%ProgramFiles%\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe` |
|
||||
| Argument | `--collect` |
|
||||
| Arbeitsverzeichnis | `%ProgramFiles%\BizTalkCheckmkPulse` |
|
||||
| Benutzer | dediziertes Dienstkonto oder gMSA |
|
||||
| Benutzer | normales dediziertes AD-Servicekonto |
|
||||
| Run level | `Limited`; keine lokale Administratorrolle erforderlich |
|
||||
| Mehrfachinstanzen | `IgnoreNew` |
|
||||
| Laufzeitlimit | 5 Minuten |
|
||||
| StartWhenAvailable | aktiv |
|
||||
| Restart | zweimal im Minutenabstand |
|
||||
|
||||
Der Task wird mit gespeichertem Dienstkontokennwort beziehungsweise gMSA
|
||||
ausgefuehrt, also unabhaengig von einer interaktiven Anmeldung.
|
||||
Der Task wird mit gespeichertem Dienstkontokennwort ausgefuehrt, also
|
||||
unabhaengig von einer interaktiven Anmeldung. Bei Kennwortwechsel oder
|
||||
-ablauf muss das Task-Kennwort aktualisiert werden. Ein gMSA ist weiterhin
|
||||
optional unterstuetzt, aber nicht die produktive Standardannahme.
|
||||
|
||||
## 8. Installation
|
||||
|
||||
@@ -304,25 +337,7 @@ scripts\test-release.cmd
|
||||
scripts\package-release.cmd
|
||||
```
|
||||
|
||||
### 8.2 gMSA
|
||||
|
||||
Voraussetzungen:
|
||||
|
||||
1. gMSA in AD erstellen und Abrufrecht auf den BizTalk-Server begrenzen.
|
||||
2. Konto lokal installieren und mit `Test-ADServiceAccount` pruefen.
|
||||
3. gMSA in die exakt konfigurierte BizTalk-Read-Only-Gruppe aufnehmen.
|
||||
4. AD-Replikation abwarten.
|
||||
|
||||
Installation:
|
||||
|
||||
```powershell
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
-CollectorAccount 'BEW\svc_biztalk_cmk$' `
|
||||
-Gmsa `
|
||||
-EnvironmentName ACC
|
||||
```
|
||||
|
||||
### 8.3 regulaeres Dienstkonto
|
||||
### 8.2 Normales Servicekonto
|
||||
|
||||
```powershell
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
@@ -333,6 +348,19 @@ Installation:
|
||||
Der Installer muss als lokaler Administrator laufen. Er vergibt keine
|
||||
AD-/BizTalk-/SQL-Rechte; diese bleiben getrennte administrative Freigaben.
|
||||
|
||||
Der installierte Task selbst laeuft mit `RunLevel Limited`. Der Installer fragt
|
||||
das Kennwort mit `Get-Credential` ab; es wird nicht in Config oder Log
|
||||
geschrieben. Das Konto benoetigt `Log on as a batch job`.
|
||||
|
||||
### 8.3 Optionales gMSA
|
||||
|
||||
```powershell
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
-CollectorAccount 'BEW\svc_biztalk_cmk$' `
|
||||
-Gmsa `
|
||||
-EnvironmentName ACC
|
||||
```
|
||||
|
||||
### 8.4 Checkmk
|
||||
|
||||
Der installierte Wrapper liegt unter:
|
||||
@@ -350,7 +378,8 @@ Snapshot nicht zusaetzlich verzoegert.
|
||||
Nach dem Agent-Dump:
|
||||
|
||||
1. Service Discovery fuer den BizTalk-Host ausfuehren.
|
||||
2. sechs stabile Services aufnehmen.
|
||||
2. acht stabile Services aufnehmen; den alten Service
|
||||
`BizTalk Runtime Artifacts` nach erfolgreicher Discovery entfernen.
|
||||
3. Changes aktivieren.
|
||||
4. Views/Benachrichtigungen nach Umgebung konfigurieren.
|
||||
|
||||
@@ -368,6 +397,12 @@ einzeilige Nachricht. Provider-Erfolge werden pro Lauf geloggt; der Consumer
|
||||
loggt nur abgelehnte Snapshots. Exceptions werden mit Typ, Nachricht,
|
||||
HRESULT-/Providerdetails und Stacktrace einzeilig gespeichert.
|
||||
|
||||
Der erfolgreiche Abschluss nennt Suspensions, Routing Failure Reports,
|
||||
Receive-Location-/Send-Port-Zahlen und Laufzeit. Jede strukturierte
|
||||
WMI-/SQL-/Event-Log-Diagnose wird zusaetzlich als eigene `WARN`-Zeile
|
||||
protokolliert und bleibt damit auch ausserhalb der gekuerzten Checkmk-Summary
|
||||
vollstaendig nachvollziehbar.
|
||||
|
||||
Logging ist best effort: Ein blockiertes Log darf Checkmk-Ausgabe oder
|
||||
Snapshot-Publikation nicht zerstoeren. Der Provider entfernt beim Start Dateien
|
||||
aelter als `LogRetentionDays`.
|
||||
@@ -391,7 +426,7 @@ Pruefen:
|
||||
1. Task existiert und ist aktiviert.
|
||||
2. `LastTaskResult` und Provider-Log.
|
||||
3. Dienstkonto kann sich als Batch anmelden.
|
||||
4. gMSA ist lokal installiert und abrufbar.
|
||||
4. gespeichertes Task-Kennwort ist nach Rotation/Ablauf noch gueltig.
|
||||
5. Provider besitzt Modify auf `data` und `logs`.
|
||||
6. EXE/Config sind ausfuehrbar.
|
||||
|
||||
@@ -468,7 +503,13 @@ Alarmierung:
|
||||
| --- | --- |
|
||||
| `WarnResumableThreshold` | `1` |
|
||||
| `CritNonResumableThreshold` | `1` |
|
||||
| `AlertOnArtifactRuntimeIssues` | `false` |
|
||||
| `CritRoutingFailureThreshold` | `1` |
|
||||
| `AlertOnArtifactRuntimeIssues` | `true` |
|
||||
| `ExpectedDisabledReceiveLocations` | leer; exakte Pipe-Liste |
|
||||
| `ExpectedInactiveSendPorts` | leer; exakte Pipe-Liste |
|
||||
| `AlertOnInactiveOrchestrations` | `false` |
|
||||
| `MaxSummaryItems` | `5` |
|
||||
| `MaxDetailCharacters` | `1600` |
|
||||
| `EmitPerApplicationSuspensionServices` | `false` |
|
||||
| `EventLogWarnThreshold` | `1` |
|
||||
| `EventLogCritThreshold` | `10` |
|
||||
@@ -478,16 +519,20 @@ Alarmierung:
|
||||
Automatisiert:
|
||||
|
||||
- Release-Build .NET Framework 4.7.2,
|
||||
- exakt sechs Self-Test-Services,
|
||||
- exakt acht Self-Test-Services,
|
||||
- unbekannte Quellen werden `UNKNOWN`,
|
||||
- dynamische Anwendungsservices nur bei bekannter Anwendung,
|
||||
- WMI-Queryvertrag nutzt dokumentierte Properties,
|
||||
- eingebetteter SQL-Loginfehler wird `Permission`,
|
||||
- abgewiesener Principal wird extrahiert,
|
||||
- Routing Failure Reports werden separat und als non-resumable gezaehlt,
|
||||
- Receive-/Send-Allowlisten trennen bewusste von unerwarteten Aus-Zustaenden,
|
||||
- ein fehlender `IsDisabled`-Wert wird `UNKNOWN` statt still als enabled,
|
||||
- betroffene Namen und Gesamtlaenge der Summary bleiben begrenzt,
|
||||
- Snapshot-Roundtrip und Ersatz,
|
||||
- SHA-256-Manipulation wird verworfen,
|
||||
- Stale-Snapshot wird verworfen,
|
||||
- Consumer-Fallback enthaelt sechs `UNKNOWN`-Services.
|
||||
- Consumer-Fallback enthaelt acht `UNKNOWN`-Services.
|
||||
|
||||
Windows-/ACC-Abnahme:
|
||||
|
||||
@@ -497,10 +542,16 @@ Windows-/ACC-Abnahme:
|
||||
4. `BizTalk Platform` zeigt `read_only_group=`.
|
||||
5. `BizTalk SQL Access`: `targets=2`, `available=2`.
|
||||
6. keine Permission-`UNKNOWN`s.
|
||||
7. ACL-Test: `LocalSystem` kann Snapshot lesen, nicht schreiben.
|
||||
8. Task deaktivieren: nach 180 Sekunden sechs stale-`UNKNOWN`s.
|
||||
9. Task wieder aktivieren: naechster Snapshot stellt Echtzustand her.
|
||||
10. Agent-Dump und Checkmk Service Discovery erfolgreich.
|
||||
7. Suspensionsmetriken mit der BizTalk Group Hub Page plausibilisieren,
|
||||
einschliesslich Routing Failure Reports.
|
||||
8. Eine bewusst deaktivierte Receive Location und einen inaktiven Send Port
|
||||
ueber die exakten Allowlisten als expected bestaetigen.
|
||||
9. Einen Testnamen aus der Allowlist entfernen und den erwarteten CRIT mit
|
||||
kurzem `affected=`-Detail pruefen.
|
||||
10. ACL-Test: `LocalSystem` kann Snapshot lesen, nicht schreiben.
|
||||
11. Task deaktivieren: nach 180 Sekunden acht stale-`UNKNOWN`s.
|
||||
12. Task wieder aktivieren: naechster Snapshot stellt Echtzustand her.
|
||||
13. Agent-Dump und Checkmk Service Discovery erfolgreich.
|
||||
|
||||
Erst nach ACC-Abnahme erfolgt der gestufte Rollout nach DEV/TST/PRD.
|
||||
|
||||
@@ -537,6 +588,10 @@ ZIP und Base64 werden erst nach dem Git-Commit aus genau diesem Commit erzeugt.
|
||||
- https://learn.microsoft.com/en-us/biztalk/core/windows-groups-and-user-accounts-in-biztalk-server
|
||||
- https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-groupsetting-biztalkreadonlyusergroup-property-wmi
|
||||
- https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-groupsetting-wmi
|
||||
- https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-serviceinstance-serviceclass-property-wmi
|
||||
- https://learn.microsoft.com/en-us/biztalk/core/types-of-message-failures
|
||||
- https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-receivelocation-isdisabled-property-wmi
|
||||
- https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-sendport-status-property-wmi
|
||||
- https://docs.checkmk.com/latest/en/agent_windows.html
|
||||
- https://docs.checkmk.com/latest/en/localchecks.html
|
||||
- https://docs.checkmk.com/latest/en/spool_directory.html
|
||||
|
||||
@@ -5,7 +5,7 @@ BizTalk Server 2020 auf Windows Server 2019. Die Anwendung trennt den
|
||||
berechtigten BizTalk-Datenzugriff vollstaendig vom Checkmk-Agenten:
|
||||
|
||||
```text
|
||||
Scheduled Task (dediziertes Dienstkonto oder gMSA)
|
||||
Scheduled Task (normales dediziertes Servicekonto)
|
||||
|
|
||||
| jede Minute: BizTalkCheckmkPulse.exe --collect
|
||||
v
|
||||
@@ -20,7 +20,7 @@ lokales BizTalk-WMI + BizTalk-SQL + Application Event Log
|
||||
Checkmk Windows Agent (LocalSystem)
|
||||
|
|
||||
v
|
||||
sechs stabile Checkmk Local Checks
|
||||
acht kompakte Checkmk Local Checks
|
||||
```
|
||||
|
||||
Damit bekommt `LocalSystem` keine BizTalk- oder SQL-Berechtigung. Nur das
|
||||
@@ -62,7 +62,7 @@ Der Datenaustausch ist bewusst defensiv:
|
||||
Checkmk-Zeilen, korrekte SHA-256-Pruefsumme und ein maximales Alter von
|
||||
standardmaessig 180 Sekunden.
|
||||
- Fehlende, veraltete, abgeschnittene, manipulierte oder unlesbare Dateien
|
||||
ergeben sechs gueltige `UNKNOWN`-Services statt einer kaputten Agent-Ausgabe.
|
||||
ergeben acht gueltige `UNKNOWN`-Services statt einer kaputten Agent-Ausgabe.
|
||||
- Ein exklusives Lock und die Task-Einstellung `IgnoreNew` verhindern
|
||||
ueberlappende Providerlaeufe.
|
||||
- Ein unerwarteter Providerfehler erzeugt nach Moeglichkeit einen aktuellen
|
||||
@@ -80,9 +80,23 @@ Standardmaessig entstehen:
|
||||
- `BizTalk SQL Access`
|
||||
- `BizTalk Suspended Instances`
|
||||
- `BizTalk Host Instances`
|
||||
- `BizTalk Runtime Artifacts`
|
||||
- `BizTalk Receive Locations`
|
||||
- `BizTalk Send Ports`
|
||||
- `BizTalk Orchestrations`
|
||||
- `BizTalk Event Log`
|
||||
|
||||
Die drei Artefaktbereiche sind absichtlich getrennte Services. Dadurch sind
|
||||
Zustand und Graphen direkt erkennbar, ohne eine lange Sammelzeile zu lesen:
|
||||
|
||||
- Suspensions: total, resumable, non-resumable und Routing Failure Reports
|
||||
- Receive Locations: total, enabled, unerwartet/bewusst disabled und unbekannt
|
||||
- Send Ports: total, started, stopped, bound, unbekannt sowie bewusst inactive
|
||||
- Orchestrations: total, started, stopped, bound, unbound und unbekannt
|
||||
|
||||
Pro Service werden standardmaessig maximal fuenf betroffene Namen gezeigt.
|
||||
Weitere Treffer erscheinen nur als `(+n more)`; Details sind zusaetzlich auf
|
||||
1600 Zeichen begrenzt. Metriken bleiben trotzdem vollstaendig.
|
||||
|
||||
Mit `EnvironmentName=ACC`, `DEV`, `TST` oder `PRD` wird die Umgebung in den
|
||||
Servicenamen aufgenommen, zum Beispiel `BizTalk ACC Platform`.
|
||||
|
||||
@@ -106,7 +120,7 @@ BizTalk-Server:
|
||||
- .NET Framework 4.7.2
|
||||
- Checkmk Windows Agent
|
||||
- administrativer Zugriff fuer die einmalige Installation
|
||||
- dediziertes AD-Dienstkonto oder bevorzugt gMSA fuer den Provider
|
||||
- normales dediziertes AD-Servicekonto fuer den Provider
|
||||
|
||||
Das Provider-Konto benoetigt:
|
||||
|
||||
@@ -116,9 +130,10 @@ Das Provider-Konto benoetigt:
|
||||
- Mitgliedschaft in der exakt konfigurierten BizTalk Server Read Only
|
||||
Users-Gruppe
|
||||
|
||||
Es soll weder lokaler Administrator noch SQL-`sysadmin` sein. Fuer ein gMSA
|
||||
muss der BizTalk-Server das verwaltete Kennwort abrufen duerfen und das Konto
|
||||
lokal installiert sein.
|
||||
Es soll weder lokaler Administrator noch SQL-`sysadmin` sein. Der Scheduled
|
||||
Task laeuft mit `RunLevel Limited`. Das Servicekonto braucht ein gespeichertes
|
||||
Task-Kennwort und das Recht `Log on as a batch job`. Ein gMSA bleibt optional,
|
||||
ist aber fuer diese Installation nicht vorausgesetzt.
|
||||
|
||||
## Build und Tests
|
||||
|
||||
@@ -146,7 +161,7 @@ Format-Self-Test ohne WMI, SQL oder Event Log:
|
||||
artifacts\BizTalkCheckmkPulse-deploy\application\BizTalkCheckmkPulse.exe --self-test
|
||||
```
|
||||
|
||||
Erwartet werden exakt sechs `OK`-Zeilen. Die Regressionstests pruefen
|
||||
Erwartet werden exakt acht `OK`-Zeilen. Die Regressionstests pruefen
|
||||
zusaetzlich Snapshot-Roundtrip, atomaren Ersatz, SHA-256-Manipulation,
|
||||
Stale-Erkennung, stabile Fallbacks und die bestehenden BizTalk-WMI-Diagnosen.
|
||||
Ein Mono-Build ist eine hilfreiche Quellcodepruefung, ersetzt aber nicht die
|
||||
@@ -167,9 +182,8 @@ Get-CimInstance `
|
||||
```
|
||||
|
||||
Ein AD-Administrator nimmt das neue Provider-Konto in
|
||||
`BizTalkReadOnlyUserGroup` auf. Bei einem gMSA endet der Kontoname mit `$`.
|
||||
Nach AD-Replikation muss ein regulaeres Dienstkonto einen neuen Anmeldetoken
|
||||
erhalten; bei gMSA wird der Task nach der Gruppenfreigabe neu gestartet.
|
||||
`BizTalkReadOnlyUserGroup` auf. Nach AD-Replikation muss das Servicekonto durch
|
||||
einen neuen Tasklauf einen neuen Anmeldetoken erhalten.
|
||||
|
||||
Die BizTalk-Konfiguration muss die Domain-Gruppe bereits als Windows-Login und
|
||||
in `BizTalkMgmtDb`, `BizTalkMsgBoxDb`, `BizTalkDTADb`,
|
||||
@@ -178,25 +192,7 @@ in `BizTalkMgmtDb`, `BizTalkMsgBoxDb`, `BizTalkDTADb`,
|
||||
SQL-Administration fuer die Gruppe repariert, nicht als Einzelberechtigung
|
||||
fuer das Provider-Konto.
|
||||
|
||||
## Installation mit gMSA
|
||||
|
||||
Deployment-Paket auf den BizTalk-Server kopieren. In administrativer Windows
|
||||
PowerShell:
|
||||
|
||||
```powershell
|
||||
Set-Location C:\Temp\BizTalkCheckmkPulse-deploy
|
||||
|
||||
# Optional, falls das gMSA noch nicht lokal installiert wurde:
|
||||
Install-ADServiceAccount -Identity svc_biztalk_cmk
|
||||
Test-ADServiceAccount -Identity svc_biztalk_cmk
|
||||
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
-CollectorAccount 'BEW\svc_biztalk_cmk$' `
|
||||
-Gmsa `
|
||||
-EnvironmentName ACC
|
||||
```
|
||||
|
||||
## Installation mit regulaerem Dienstkonto
|
||||
## Installation mit normalem Servicekonto
|
||||
|
||||
```powershell
|
||||
Set-Location C:\Temp\BizTalkCheckmkPulse-deploy
|
||||
@@ -209,6 +205,13 @@ Der Installer fragt das Kennwort ueber `Get-Credential` ab und speichert es
|
||||
durch die Windows-Aufgabenplanung. Das Kennwort steht weder in der
|
||||
Konfigurationsdatei noch in den Logs.
|
||||
|
||||
Wenn das Kennwort rotiert oder ablaeuft, muss es im Scheduled Task aktualisiert
|
||||
werden. Bis dahin wird der Snapshot nach 180 Sekunden stale und Checkmk zeigt
|
||||
alle acht Services als `UNKNOWN`.
|
||||
|
||||
Ein gMSA kann weiterhin optional mit `-Gmsa` installiert werden; die
|
||||
produktive Standardbeschreibung geht vom normalen Servicekonto aus.
|
||||
|
||||
Der Installer:
|
||||
|
||||
1. kopiert EXE und Config nach
|
||||
@@ -265,7 +268,7 @@ Verbindlicher Test im echten `LocalSystem`-Kontext:
|
||||
Select-String -Pattern "BizTalk|UNKNOWN|Snapshot|Permission" -Context 0,1
|
||||
```
|
||||
|
||||
Danach in Checkmk eine Service Discovery ausfuehren, die sechs Services
|
||||
Danach in Checkmk eine Service Discovery ausfuehren, die acht Services
|
||||
aufnehmen und Changes aktivieren. Ein zusaetzlicher Checkmk-Async-Cache ist
|
||||
nicht erforderlich: Der Consumer liest nur eine kleine lokale Datei und der
|
||||
Provider besitzt bereits seinen eigenen Minutentakt.
|
||||
@@ -322,7 +325,13 @@ Wichtige Werte:
|
||||
| `SqlConnectionTimeoutSeconds` | `5` | SQL-Timeout je Ziel. |
|
||||
| `WarnResumableThreshold` | `1` | WARN ab n resumable Suspensions. |
|
||||
| `CritNonResumableThreshold` | `1` | CRIT ab n non-resumable Suspensions. |
|
||||
| `AlertOnArtifactRuntimeIssues` | `false` | WARN fuer bewusst inaktive Artefakte aktivieren. |
|
||||
| `CritRoutingFailureThreshold` | `1` | CRIT ab n Routing Failure Reports. |
|
||||
| `AlertOnArtifactRuntimeIssues` | `true` | Unerwartet deaktivierte Receive Locations bzw. inaktive Send Ports werden CRIT. |
|
||||
| `ExpectedDisabledReceiveLocations` | leer | Pipe-getrennte exakte Allowlist: `Name` oder `Anwendung\Name`. |
|
||||
| `ExpectedInactiveSendPorts` | leer | Pipe-getrennte exakte Allowlist: `Name` oder `Anwendung\Name`. |
|
||||
| `AlertOnInactiveOrchestrations` | `false` | Optional WARN fuer stopped/bound/unbound Orchestrations. |
|
||||
| `MaxSummaryItems` | `5` | Maximal angezeigte betroffene Artefakte je Service. |
|
||||
| `MaxDetailCharacters` | `1600` | Harte Obergrenze fuer Checkmk-Summary. |
|
||||
| `EmitPerApplicationSuspensionServices` | `false` | Zusaetzliche Anwendungsservices. |
|
||||
| `EventLogLookbackMinutes` | `60` | Event-Log-Zeitfenster des Providers. |
|
||||
|
||||
@@ -333,10 +342,11 @@ liest den naechsten atomar publizierten Snapshot.
|
||||
|
||||
| Beobachtung | Ursache / Massnahme |
|
||||
| --- | --- |
|
||||
| Alle sechs Services melden fehlenden Snapshot | Task, Provider-Log, Task-Konto und ACL pruefen. |
|
||||
| Alle acht Services melden fehlenden Snapshot | Task, Provider-Log, Task-Konto/Kennwort und ACL pruefen. |
|
||||
| Snapshot ist `stale` | `LastTaskResult`, Laufzeit, WMI-/SQL-Timeout und Log pruefen. |
|
||||
| SHA-256 oder Format ungueltig | Datei nicht manuell bearbeiten; Datentraeger/AV und Schreibpfad pruefen, Task neu starten. |
|
||||
| Provider meldet `Login failed` | Provider-Konto und exakt konfigurierte Read-Only-Gruppe sowie `BTS_READONLY_USERS` pruefen. |
|
||||
| Receive Locations / Send Ports sind CRIT | `affected=` pruefen; nur fachlich bewusst inaktive Namen exakt in die jeweilige Allowlist aufnehmen. |
|
||||
| `Wmi/Schema` | Klasse/Properties gegen BizTalk-2020-Schema pruefen; keine Rechte ausweiten. |
|
||||
| Nur Event Log `UNKNOWN` | lokalen Application-Log-Zugriff des Provider-Kontos pruefen. |
|
||||
| Task-Result `2` | Parallelstart oder Snapshot-I/O; Log und Lock/ACL pruefen. |
|
||||
|
||||
@@ -128,7 +128,7 @@ if ($Gmsa) {
|
||||
$principal = New-ScheduledTaskPrincipal `
|
||||
-UserId $CollectorAccount `
|
||||
-LogonType Password `
|
||||
-RunLevel Highest
|
||||
-RunLevel Limited
|
||||
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -Principal $principal
|
||||
Register-ScheduledTask -TaskName $taskName -InputObject $task -Force | Out-Null
|
||||
}
|
||||
@@ -143,7 +143,7 @@ else {
|
||||
$principal = New-ScheduledTaskPrincipal `
|
||||
-UserId $CollectorAccount `
|
||||
-LogonType Password `
|
||||
-RunLevel Highest
|
||||
-RunLevel Limited
|
||||
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -Principal $principal
|
||||
Register-ScheduledTask `
|
||||
-TaskName $taskName `
|
||||
@@ -155,8 +155,8 @@ else {
|
||||
|
||||
Write-Host "Fuehre formatseitigen Self-Test aus ..."
|
||||
$selfTest = & $targetExe --self-test
|
||||
if ($LASTEXITCODE -ne 0 -or @($selfTest).Count -ne 6) {
|
||||
throw "Self-Test fehlgeschlagen. Erwartet wurden sechs Checkmk-Zeilen."
|
||||
if ($LASTEXITCODE -ne 0 -or @($selfTest).Count -ne 8) {
|
||||
throw "Self-Test fehlgeschlagen. Erwartet wurden acht Checkmk-Zeilen."
|
||||
}
|
||||
|
||||
Write-Host "Starte den Provider einmalig ..."
|
||||
|
||||
@@ -9,7 +9,9 @@ if not exist "%EXE%" (
|
||||
echo 3 "BizTalk SQL Access" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||
echo 3 "BizTalk Suspended Instances" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||
echo 3 "BizTalk Host Instances" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||
echo 3 "BizTalk Runtime Artifacts" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||
echo 3 "BizTalk Receive Locations" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||
echo 3 "BizTalk Send Ports" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||
echo 3 "BizTalk Orchestrations" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||
echo 3 "BizTalk Event Log" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||
exit /b 0
|
||||
)
|
||||
@@ -21,7 +23,9 @@ if not "%EXITCODE%"=="0" (
|
||||
echo 3 "BizTalk SQL Access" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: .NET Framework 4.7.2, EXE/Config-Dateien und Windows Application Log pruefen.
|
||||
echo 3 "BizTalk Suspended Instances" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: Programmstart und Windows Application Log pruefen.
|
||||
echo 3 "BizTalk Host Instances" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: Programmstart und Windows Application Log pruefen.
|
||||
echo 3 "BizTalk Runtime Artifacts" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: Programmstart und Windows Application Log pruefen.
|
||||
echo 3 "BizTalk Receive Locations" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: Programmstart und Provider-Log pruefen.
|
||||
echo 3 "BizTalk Send Ports" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: Programmstart und Provider-Log pruefen.
|
||||
echo 3 "BizTalk Orchestrations" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: Programmstart und Provider-Log pruefen.
|
||||
echo 3 "BizTalk Event Log" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: Programmstart und Windows Application Log pruefen.
|
||||
)
|
||||
exit /b 0
|
||||
|
||||
@@ -18,7 +18,7 @@ NEUE VERBINDLICHE ARCHITEKTUR
|
||||
|
||||
Das Maschinenkonto erhaelt keine BizTalk-Berechtigung.
|
||||
|
||||
1. Ein dediziertes Dienstkonto oder bevorzugt gMSA laeuft minuetlich als
|
||||
1. Ein normales dediziertes Servicekonto laeuft minuetlich als
|
||||
Scheduled Task "BizTalk Checkmk Pulse Provider".
|
||||
2. Dieses Konto fuehrt BizTalkCheckmkPulse.exe --collect aus.
|
||||
3. Es schreibt atomar einen SHA-256-geschuetzten Snapshot nach:
|
||||
@@ -64,14 +64,7 @@ NICHT DURCHFUEHREN
|
||||
INSTALLATION
|
||||
============
|
||||
|
||||
gMSA:
|
||||
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
-CollectorAccount 'BEW\svc_biztalk_cmk$' `
|
||||
-Gmsa `
|
||||
-EnvironmentName ACC
|
||||
|
||||
Regulaeres Dienstkonto:
|
||||
Normales Servicekonto:
|
||||
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
-CollectorAccount 'BEW\svc_biztalk_cmk' `
|
||||
@@ -102,6 +95,8 @@ ERWARTET
|
||||
- Provider-Log nennt das dedizierte Konto
|
||||
- BizTalk Platform zeigt read_only_group=<exakte Gruppe>
|
||||
- BizTalk SQL Access zeigt targets=2 und available=2
|
||||
- Suspensionsmetriken enthalten resumable, non-resumable und Routing Failure Reports
|
||||
- Receive Locations und Send Ports trennen expected von unexpected inactive
|
||||
- keine berechtigungsbedingten UNKNOWN-Services
|
||||
- LocalSystem besitzt auf data nur Lesezugriff
|
||||
|
||||
|
||||
+64
-14
@@ -11,7 +11,7 @@ Die Ausgabe ist so gebaut, dass sie auch mit Checkmk 2.4.0p4 kompatibel bleibt:
|
||||
Die fachlichen Daten werden minuetlich vom privilegierten Scheduled-Task-
|
||||
Provider erzeugt. Der Checkmk-Agent liest als `LocalSystem` nur den
|
||||
integritaets- und altersgeprueften Snapshot. Ist dieser Transport nicht
|
||||
verfuegbar, liefern alle sechs stabilen Services `UNKNOWN`.
|
||||
verfuegbar, liefern alle acht stabilen Services `UNKNOWN`.
|
||||
|
||||
## BizTalk Platform
|
||||
|
||||
@@ -77,6 +77,7 @@ Zweck:
|
||||
|
||||
- Ermittelt suspendierte BizTalk-Service-Instanzen.
|
||||
- Unterscheidet resumable und non-resumable.
|
||||
- Zaehlt Routing Failure Reports (`ServiceClass=64`) separat.
|
||||
- Zeigt betroffene Anwendungen und Beispiele in der Summary.
|
||||
|
||||
Status:
|
||||
@@ -86,6 +87,7 @@ Status:
|
||||
| `OK` | keine suspendierten Instanzen. |
|
||||
| `WARN` | `biztalk_suspended_resumable >= WarnResumableThreshold`. |
|
||||
| `CRIT` | `biztalk_suspended_nonresumable >= CritNonResumableThreshold`. |
|
||||
| `CRIT` | `biztalk_routing_failure_reports >= CritRoutingFailureThreshold`. |
|
||||
| `UNKNOWN` | `MSBTS_ServiceInstance` nicht verlaesslich lesbar oder Programmfehler. |
|
||||
|
||||
Metriken:
|
||||
@@ -95,6 +97,7 @@ Metriken:
|
||||
| `biztalk_suspended_total` | Summe aller suspendierten Instanzen. |
|
||||
| `biztalk_suspended_resumable` | Resumable suspended instances. |
|
||||
| `biztalk_suspended_nonresumable` | Non-resumable suspended instances. |
|
||||
| `biztalk_routing_failure_reports` | Routing Failure Reports; Teilmenge der non-resumable Instanzen. |
|
||||
|
||||
## BizTalk Host Instances
|
||||
|
||||
@@ -123,38 +126,85 @@ Metriken:
|
||||
| `biztalk_host_instances_pending` | StartPending/StopPending. |
|
||||
| `biztalk_host_instances_unknown` | Nicht interpretierbarer Status. |
|
||||
|
||||
## BizTalk Runtime Artifacts
|
||||
## BizTalk Receive Locations
|
||||
|
||||
Zweck:
|
||||
|
||||
- Summiert Laufzeitzustaende von Receive Locations, Send Ports und Orchestrations.
|
||||
- Liefert dashboard-taugliche Zahlen zur Laufzeitlandschaft.
|
||||
- Zaehlt alle konfigurierten Receive Locations und ihren `IsDisabled`-Zustand.
|
||||
- Trennt bewusst deaktivierte von unerwartet deaktivierten Namen.
|
||||
|
||||
Status:
|
||||
|
||||
| Status | Bedingung |
|
||||
| --- | --- |
|
||||
| `OK` | Artefakte lesbar; keine unbekannten Statuswerte. |
|
||||
| `WARN` | Nur bei `AlertOnArtifactRuntimeIssues=true` und inaktiven/deaktivierten Artefakten. |
|
||||
| `CRIT` | Unbekannte Send-Port- oder Orchestration-Statuswerte. |
|
||||
| `UNKNOWN` | Mindestens eine erforderliche Artefaktklasse nicht lesbar oder Programmfehler. |
|
||||
| `OK` | Daten lesbar und keine unerwartet deaktivierte Receive Location. |
|
||||
| `CRIT` | Mindestens eine unerwartet deaktivierte Receive Location bei `AlertOnArtifactRuntimeIssues=true`. |
|
||||
| `UNKNOWN` | `MSBTS_ReceiveLocation` nicht verlaesslich lesbar oder `IsDisabled` eines Objekts nicht interpretierbar. |
|
||||
|
||||
Metriken:
|
||||
|
||||
| Metrik | Bedeutung |
|
||||
| --- | --- |
|
||||
| `biztalk_applications` | Anzahl der per WMI erkannten Anwendungs-Buckets; `(unknown)` ist moeglich, da die dokumentierten Artefaktklassen keine verlaessliche Application-Property garantieren. |
|
||||
| `biztalk_receive_locations` | Gesamtzahl Receive Locations. |
|
||||
| `biztalk_receive_locations_total` | Gesamtzahl Receive Locations. |
|
||||
| `biztalk_receive_locations_enabled` | Aktivierte Receive Locations. |
|
||||
| `biztalk_receive_locations_disabled` | Deaktivierte Receive Locations. |
|
||||
| `biztalk_send_ports` | Gesamtzahl Send Ports. |
|
||||
| `biztalk_receive_locations_unexpected_disabled` | Deaktiviert und nicht in der Allowlist; CRIT ab 1. |
|
||||
| `biztalk_receive_locations_expected_disabled` | Bewusst deaktiviert und exakt allowlisted. |
|
||||
| `biztalk_receive_locations_unknown` | Fehlender oder nicht interpretierbarer `IsDisabled`-Wert. |
|
||||
|
||||
## BizTalk Send Ports
|
||||
|
||||
Status:
|
||||
|
||||
| Status | Bedingung |
|
||||
| --- | --- |
|
||||
| `OK` | Alle nicht allowlisted Send Ports sind started. |
|
||||
| `CRIT` | Mindestens ein unerwartet stopped/bound Port oder unbekannter Status. |
|
||||
| `UNKNOWN` | `MSBTS_SendPort` nicht verlaesslich lesbar. |
|
||||
|
||||
Metriken:
|
||||
|
||||
| Metrik | Bedeutung |
|
||||
| --- | --- |
|
||||
| `biztalk_send_ports_total` | Gesamtzahl Send Ports. |
|
||||
| `biztalk_send_ports_started` | Gestartete Send Ports. |
|
||||
| `biztalk_send_ports_inactive` | Bound oder stopped Send Ports. |
|
||||
| `biztalk_send_ports_stopped` | Enlisted, Subscription deaktiviert (`Status=2`). |
|
||||
| `biztalk_send_ports_bound` | Bound/unenlisted (`Status=1`). |
|
||||
| `biztalk_send_ports_unexpected_inactive` | Stopped/bound und nicht allowlisted; CRIT ab 1. |
|
||||
| `biztalk_send_ports_expected_inactive` | Bewusst inactive und exakt allowlisted. |
|
||||
| `biztalk_send_ports_unknown` | Nicht interpretierbarer Send-Port-Status. |
|
||||
| `biztalk_orchestrations` | Gesamtzahl Orchestrations. |
|
||||
|
||||
## BizTalk Orchestrations
|
||||
|
||||
Status:
|
||||
|
||||
| Status | Bedingung |
|
||||
| --- | --- |
|
||||
| `OK` | Daten lesbar und kein unbekannter Status; inaktive Orchestrations sind standardmaessig nur Information. |
|
||||
| `WARN` | stopped/bound/unbound bei `AlertOnInactiveOrchestrations=true`. |
|
||||
| `CRIT` | Mindestens ein unbekannter Statuswert. |
|
||||
| `UNKNOWN` | `MSBTS_Orchestration` nicht verlaesslich lesbar. |
|
||||
|
||||
Metriken:
|
||||
|
||||
| Metrik | Bedeutung |
|
||||
| --- | --- |
|
||||
| `biztalk_orchestrations_total` | Gesamtzahl Orchestrations. |
|
||||
| `biztalk_orchestrations_started` | Gestartete Orchestrations. |
|
||||
| `biztalk_orchestrations_inactive` | Bound, unbound oder stopped Orchestrations. |
|
||||
| `biztalk_orchestrations_stopped` | Gestoppte Orchestrations. |
|
||||
| `biztalk_orchestrations_bound` | Bound Orchestrations. |
|
||||
| `biztalk_orchestrations_unbound` | Unbound Orchestrations. |
|
||||
| `biztalk_orchestrations_unknown` | Nicht interpretierbarer Orchestration-Status. |
|
||||
|
||||
Allowlist-Syntax fuer Receive Locations und Send Ports:
|
||||
|
||||
```text
|
||||
Name|Anwendung\Name|Weiterer Name
|
||||
```
|
||||
|
||||
Die Auswertung ist case-insensitive und exakt. Wildcards werden bewusst nicht
|
||||
unterstuetzt, damit eine breite Regel keine neuen Artefaktfehler verdeckt.
|
||||
|
||||
## BizTalk Event Log
|
||||
|
||||
Zweck:
|
||||
|
||||
+33
-21
@@ -7,54 +7,66 @@
|
||||
0 "BizTalk SQL Access" biztalk_sql_targets_total=0;;;0 Self test OK. No SQL connection was opened.
|
||||
0 "BizTalk Suspended Instances" biztalk_suspended_total=0;;;0 Self test OK.
|
||||
0 "BizTalk Host Instances" biztalk_host_instances_total=0;;;0 Self test OK. No WMI query was executed.
|
||||
0 "BizTalk Runtime Artifacts" biztalk_applications=0;;;0 Self test OK. No WMI query was executed.
|
||||
0 "BizTalk Receive Locations" biztalk_receive_locations_total=0;;;0 Self test OK. No WMI query was executed.
|
||||
0 "BizTalk Send Ports" biztalk_send_ports_total=0;;;0 Self test OK. No WMI query was executed.
|
||||
0 "BizTalk Orchestrations" biztalk_orchestrations_total=0;;;0 Self test OK. No WMI query was executed.
|
||||
0 "BizTalk Event Log" biztalk_eventlog_errors=0;;;0 Self test OK. No event log was read.
|
||||
```
|
||||
|
||||
## Gesunder BizTalk-Server
|
||||
## Gesundes kompaktes Servicebild
|
||||
|
||||
```text
|
||||
0 "BizTalk Platform" - BizTalk WMI and platform data reachable, server=BIZTALK01, group=BizTalkMgmtDb, read_only_group=CONTOSO\BizTalk Server Read Only Users, operator_group=CONTOSO\BizTalk Server Operators, mgmt_db=SQL01\BizTalkMgmtDb, msgbox_db=SQL01\BizTalkMsgBoxDb
|
||||
0 "BizTalk SQL Access" biztalk_sql_targets_total=2;;;0|biztalk_sql_targets_available=2;;;0|biztalk_sql_targets_failed=0;;1;0 SQL access targets=2, available=2, discovery_complete=True, execution_identity=CONTOSO\svc_biztalk_cmk$, network_identity=CONTOSO\svc_biztalk_cmk$; databases=Management=SQL01\BizTalkMgmtDb:OK, MasterMessageBox=SQL01\BizTalkMsgBoxDb:OK
|
||||
0 "BizTalk Suspended Instances" biztalk_suspended_total=0;;;0|biztalk_suspended_resumable=0;1;;0|biztalk_suspended_nonresumable=0;;1;0 No suspended BizTalk service instances found.
|
||||
0 "BizTalk Host Instances" biztalk_host_instances_total=4;;;0|biztalk_host_instances_started=4;;;0|biztalk_host_instances_stopped=0;;1;0|biztalk_host_instances_pending=0;1;;0|biztalk_host_instances_unknown=0;;1;0 Host instances total=4, started=4, stopped=0, pending=0, unknown=0
|
||||
0 "BizTalk Runtime Artifacts" biztalk_applications=8;;;0|biztalk_receive_locations=24;;;0|biztalk_receive_locations_disabled=0;1;;0|biztalk_send_ports=31;;;0|biztalk_send_ports_started=31;;;0|biztalk_send_ports_inactive=0;1;;0|biztalk_send_ports_unknown=0;;1;0|biztalk_orchestrations=12;;;0|biztalk_orchestrations_started=12;;;0|biztalk_orchestrations_inactive=0;1;;0|biztalk_orchestrations_unknown=0;;1;0 Applications=8; receive_locations total=24, disabled=0; send_ports total=31, started=31, inactive=0, unknown=0; orchestrations total=12, started=12, inactive=0, unknown=0
|
||||
0 "BizTalk Event Log" biztalk_eventlog_errors=0;1;10;0|biztalk_eventlog_warnings=0;1;;0 BizTalk-related Application log entries in last 60 minutes: errors=0, warnings=0
|
||||
0 "BizTalk Suspended Instances" biztalk_suspended_total=0;;;0|biztalk_suspended_resumable=0;1;;0|biztalk_suspended_nonresumable=0;;1;0|biztalk_routing_failure_reports=0;;1;0 Suspended total=0, resumable=0, nonresumable=0, routing_failure_reports=0.
|
||||
0 "BizTalk Receive Locations" biztalk_receive_locations_total=24;;;0|biztalk_receive_locations_enabled=23;;;0|biztalk_receive_locations_disabled=1;;;0|biztalk_receive_locations_unexpected_disabled=0;;1;0|biztalk_receive_locations_expected_disabled=1;;;0|biztalk_receive_locations_unknown=0;;1;0 Receive locations total=24, enabled=23, unexpected_disabled=0, expected_disabled=1, unknown=0
|
||||
0 "BizTalk Send Ports" biztalk_send_ports_total=31;;;0|biztalk_send_ports_started=30;;;0|biztalk_send_ports_stopped=1;;;0|biztalk_send_ports_bound=0;;;0|biztalk_send_ports_unexpected_inactive=0;;1;0|biztalk_send_ports_expected_inactive=1;;;0|biztalk_send_ports_unknown=0;;1;0 Send ports total=31, started=30, stopped=1, bound=0, unexpected_inactive=0, expected_inactive=1, unknown=0
|
||||
0 "BizTalk Orchestrations" biztalk_orchestrations_total=12;;;0|biztalk_orchestrations_started=11;;;0|biztalk_orchestrations_stopped=1;;;0|biztalk_orchestrations_bound=0;;;0|biztalk_orchestrations_unbound=0;;;0|biztalk_orchestrations_unknown=0;;1;0 Orchestrations total=12, started=11, stopped=1, bound=0, unbound=0, unknown=0; affected_apps=Maintenance(inactive=1,unknown=0)
|
||||
```
|
||||
|
||||
## Suspended Instances
|
||||
Die bewusst inaktiven Receive-/Send-Artefakte stehen in den exakten
|
||||
Allowlisten. Sie bleiben als Metrik sichtbar, erzeugen aber keinen Alarm.
|
||||
|
||||
## Suspensions und Routing Failure Report
|
||||
|
||||
```text
|
||||
2 "BizTalk Suspended Instances" biztalk_suspended_total=3;;;0|biztalk_suspended_resumable=2;1;;0|biztalk_suspended_nonresumable=1;;1;0 3 suspended BizTalk service instance(s): resumable=2, nonresumable=1; applications=OrderProcessing(R=2, NR=1); examples=Send.Invoice on ProcessingHost
|
||||
2 "BizTalk Suspended Instances" biztalk_suspended_total=3;;;0|biztalk_suspended_resumable=2;1;;0|biztalk_suspended_nonresumable=1;;1;0|biztalk_routing_failure_reports=1;;1;0 Suspended total=3, resumable=2, nonresumable=1, routing_failure_reports=1; applications=OrderProcessing(R=2,NR=0); recent=Receive.Order@ProcessingHost, Send.Invoice@ProcessingHost
|
||||
```
|
||||
|
||||
## SQL-Berechtigungsfehler
|
||||
Routing Failure Reports sind eine Teilmenge der non-resumable Instanzen und
|
||||
werden nicht doppelt zum Total addiert.
|
||||
|
||||
## Unerwartet deaktivierte Receive Locations
|
||||
|
||||
```text
|
||||
3 "BizTalk SQL Access" biztalk_sql_targets_total=2;;;0|biztalk_sql_targets_available=0;;;0|biztalk_sql_targets_failed=2;;1;0 SQL access targets=2, available=0, discovery_complete=True, execution_identity=CONTOSO\svc_biztalk_cmk$, network_identity=CONTOSO\svc_biztalk_cmk$; databases=Management=SQL01\BizTalkMgmtDb:FAILED, MasterMessageBox=SQL01\BizTalkMsgBoxDb:FAILED; diagnostics: Sql/Permission [Management SQL01\BizTalkMgmtDb]: SQL Server hat die integrierte Anmeldung abgelehnt. Massnahme: Provider-Konto und konfigurierte BizTalk-Read-Only-Gruppe mit BTS_READONLY_USERS pruefen; keine direkten BizTalk-DB-Rollen vergeben. Technik: SqlException Number=18456: Login failed for user
|
||||
2 "BizTalk Receive Locations" biztalk_receive_locations_total=24;;;0|biztalk_receive_locations_enabled=22;;;0|biztalk_receive_locations_disabled=2;;;0|biztalk_receive_locations_unexpected_disabled=1;;1;0|biztalk_receive_locations_expected_disabled=1;;;0|biztalk_receive_locations_unknown=0;;1;0 Receive locations total=24, enabled=22, unexpected_disabled=1, expected_disabled=1, unknown=0; affected=Orders\RL_Order_In
|
||||
```
|
||||
|
||||
## WMI-Berechtigungsfehler
|
||||
## Unerwartet inaktive Send Ports
|
||||
|
||||
```text
|
||||
3 "BizTalk Suspended Instances" - Suspendierte Instanzen konnten nicht verlaesslich gelesen werden. Ein leerer Datenbestand wird nicht als OK gewertet.; diagnostics: Wmi/Permission [MSBTS_ServiceInstance]: Zugriff des Provider-Kontos auf MSBTS_ServiceInstance wurde verweigert. Massnahme: Provider-Identitaet und konfigurierte BizTalk-Read-Only-Gruppe pruefen. Technik: UnauthorizedAccessException HRESULT=0x80070005: Access is denied
|
||||
2 "BizTalk Send Ports" biztalk_send_ports_total=31;;;0|biztalk_send_ports_started=29;;;0|biztalk_send_ports_stopped=1;;;0|biztalk_send_ports_bound=1;;;0|biztalk_send_ports_unexpected_inactive=1;;1;0|biztalk_send_ports_expected_inactive=1;;;0|biztalk_send_ports_unknown=0;;1;0 Send ports total=31, started=29, stopped=1, bound=1, unexpected_inactive=1, expected_inactive=1, unknown=0; affected=Orders\SP_Order_Out(bound)
|
||||
```
|
||||
|
||||
## Begrenzte Detailausgabe
|
||||
|
||||
```text
|
||||
2 "BizTalk Receive Locations" ... affected=App\RL1, App\RL2, App\RL3, App\RL4, App\RL5 (+17 more)
|
||||
```
|
||||
|
||||
Die Zaehler und Performance-Daten enthalten weiterhin alle 22 betroffenen
|
||||
Artefakte. Nur die Textliste ist begrenzt.
|
||||
|
||||
## Fehlender oder veralteter Provider-Snapshot
|
||||
|
||||
Alle acht Services werden `UNKNOWN`, zum Beispiel:
|
||||
|
||||
```text
|
||||
3 "BizTalk Platform" - Privilegierter BizTalk-Datensnapshot nicht verfuegbar: Snapshot is stale: age=241s, maximum=180s. Massnahme: Scheduled Task 'BizTalk Checkmk Pulse Provider', Provider-Log, Snapshot-Alter und ACL pruefen.
|
||||
3 "BizTalk SQL Access" - Privilegierter BizTalk-Datensnapshot nicht verfuegbar: Snapshot is stale: age=241s, maximum=180s. Massnahme: Scheduled Task 'BizTalk Checkmk Pulse Provider', Provider-Log, Snapshot-Alter und ACL pruefen.
|
||||
```
|
||||
|
||||
## WMI-Schemafehler
|
||||
|
||||
```text
|
||||
3 "BizTalk Runtime Artifacts" - BizTalk Runtime Artifacts konnten nicht vollstaendig gelesen werden. Teilwerte werden nicht als OK gewertet.; diagnostics: Wmi/Schema [MSBTS_Orchestration]: WMI-Klasse oder WQL fuer MSBTS_Orchestration wird vom installierten BizTalk-Provider nicht unterstuetzt. Massnahme: Klassen- und Property-Namen gegen das installierte BizTalk-WMI-Schema und die Microsoft-Dokumentation pruefen. Rechteerhoehung behebt InvalidClass/InvalidQuery nicht. Technik: ManagementException HRESULT=0x80041010: Invalid class WQL={SELECT * FROM MSBTS_Orchestration} DurationMs=18
|
||||
```
|
||||
|
||||
## Fehlendes Deployment
|
||||
Nur der fachlich betroffene Service wird `UNKNOWN`:
|
||||
|
||||
```text
|
||||
3 "BizTalk Platform" - BizTalkCheckmkPulse.exe fehlt unter C:\Program Files\BizTalkCheckmkPulse. Massnahme: Install-BizTalkCheckmkPulse.ps1 erneut als Administrator ausfuehren und danach cmk-agent-ctl.exe dump erneut ausfuehren.
|
||||
3 "BizTalk Orchestrations" - Orchestrations konnten nicht verlaesslich gelesen werden.; diagnostics: Wmi/Schema [MSBTS_Orchestration]: WMI-Klasse oder WQL wird nicht unterstuetzt. Massnahme: Klassen- und Property-Namen gegen das installierte BizTalk-WMI-Schema pruefen.
|
||||
```
|
||||
|
||||
+7
-13
@@ -4,7 +4,7 @@
|
||||
|
||||
| Team | Aufgabe |
|
||||
| --- | --- |
|
||||
| AD/Security | dediziertes Dienstkonto oder gMSA; Aufnahme in exakt konfigurierte BizTalk-Read-Only-Gruppe |
|
||||
| AD/Security | normales dediziertes Servicekonto; Aufnahme in exakt konfigurierte BizTalk-Read-Only-Gruppe |
|
||||
| BizTalk/SQL | Gruppenabbildung und `BTS_READONLY_USERS` bestaetigen; keine Einzelrechte |
|
||||
| Windows | Paket installieren, ACL und Scheduled Task pruefen |
|
||||
| Checkmk | Wrapper verteilen beziehungsweise Installation koordinieren, Discovery und Alarmierung |
|
||||
@@ -15,16 +15,7 @@ Provider-Konto und publiziert einen validierbaren Snapshot.
|
||||
|
||||
## Installation
|
||||
|
||||
gMSA:
|
||||
|
||||
```powershell
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
-CollectorAccount 'BEW\svc_biztalk_cmk$' `
|
||||
-Gmsa `
|
||||
-EnvironmentName ACC
|
||||
```
|
||||
|
||||
Regulaeres Dienstkonto:
|
||||
Normales Servicekonto:
|
||||
|
||||
```powershell
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
@@ -70,7 +61,8 @@ Verbindlicher Agent-Dump:
|
||||
2. `LastTaskResult=0`, frischen Snapshot und Log pruefen.
|
||||
3. Agent-Dump im `LocalSystem`-Kontext pruefen.
|
||||
4. Service Discovery fuer den BizTalk-Host ausfuehren.
|
||||
5. sechs stabile Services aufnehmen.
|
||||
5. acht stabile Services aufnehmen und den alten
|
||||
`BizTalk Runtime Artifacts`-Service entfernen.
|
||||
6. Changes aktivieren.
|
||||
7. Views, Servicegruppen und Benachrichtigungen einrichten.
|
||||
|
||||
@@ -117,11 +109,13 @@ Soll:
|
||||
- Log nennt das dedizierte Providerkonto.
|
||||
- Platform zeigt `read_only_group=...`.
|
||||
- SQL Access zeigt `targets=2`, `available=2`.
|
||||
- Suspended Instances zeigt total/resumable/non-resumable/routing failures.
|
||||
- Receive Locations und Send Ports zeigen getrennte expected/unexpected Werte.
|
||||
- keine berechtigungsbedingten `UNKNOWN`-Services.
|
||||
|
||||
## Alarmierung der Transportkette
|
||||
|
||||
Ein Ausfall des Providers wird ueber alle sechs Services als `UNKNOWN`
|
||||
Ein Ausfall des Providers wird ueber alle acht Services als `UNKNOWN`
|
||||
sichtbar. Die Summary nennt fehlenden, unlesbaren, ungueltigen oder stale
|
||||
Snapshot. Als Betriebsregel sollte `UNKNOWN` dieser Services genauso
|
||||
eskaliert werden wie ein technischer Monitoringausfall.
|
||||
|
||||
@@ -20,10 +20,17 @@
|
||||
<add key="SqlConnectionTimeoutSeconds" value="5" />
|
||||
<add key="WarnResumableThreshold" value="1" />
|
||||
<add key="CritNonResumableThreshold" value="1" />
|
||||
<add key="MaxSummaryItems" value="12" />
|
||||
<add key="CritRoutingFailureThreshold" value="1" />
|
||||
<add key="MaxSummaryItems" value="5" />
|
||||
<add key="MaxDetailCharacters" value="1600" />
|
||||
|
||||
<!-- Gestoppte Artefakte koennen in BizTalk-Landschaften fachlich beabsichtigt sein. -->
|
||||
<add key="AlertOnArtifactRuntimeIssues" value="false" />
|
||||
<!-- Unerwartet deaktivierte Receive Locations und inaktive Send Ports sind standardmaessig CRIT. -->
|
||||
<add key="AlertOnArtifactRuntimeIssues" value="true" />
|
||||
<!-- Exakte Namen, Pipe-getrennt: Name oder Anwendung\Name. Keine Wildcards. -->
|
||||
<add key="ExpectedDisabledReceiveLocations" value="" />
|
||||
<add key="ExpectedInactiveSendPorts" value="" />
|
||||
<!-- Gestoppte/bound Orchestrations koennen fachlich beabsichtigt sein. -->
|
||||
<add key="AlertOnInactiveOrchestrations" value="false" />
|
||||
<add key="EmitPerApplicationSuspensionServices" value="false" />
|
||||
|
||||
<add key="ProbeEventLog" value="true" />
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace BizTalkCheckmkPulse
|
||||
private const int HostPausePending = 6;
|
||||
private const int HostPaused = 7;
|
||||
private const int HostUnknown = 8;
|
||||
private const int SendPortBound = 1;
|
||||
private const int SendPortStopped = 2;
|
||||
private const int SendPortStarted = 3;
|
||||
private readonly MonitoringOptions _options;
|
||||
|
||||
/// <summary>
|
||||
@@ -41,7 +44,9 @@ namespace BizTalkCheckmkPulse
|
||||
yield return FormatSqlAccess(result);
|
||||
yield return FormatSuspendedInstances(result);
|
||||
yield return FormatHostInstances(result);
|
||||
yield return FormatRuntimeArtifacts(result);
|
||||
yield return FormatReceiveLocations(result);
|
||||
yield return FormatSendPorts(result);
|
||||
yield return FormatOrchestrations(result);
|
||||
yield return FormatEventLog(result);
|
||||
|
||||
if (_options.EmitPerApplicationSuspensionServices && result.Platform.SuspendedInstancesDataAvailable)
|
||||
@@ -63,7 +68,9 @@ namespace BizTalkCheckmkPulse
|
||||
yield return BuildLine(CheckState.Ok, _options.ServiceName("SQL Access"), "biztalk_sql_targets_total=0;;;0", "Self test OK. No SQL connection was opened.");
|
||||
yield return BuildLine(CheckState.Ok, _options.ServiceName("Suspended Instances"), "biztalk_suspended_total=0;;;0", "Self test OK.");
|
||||
yield return BuildLine(CheckState.Ok, _options.ServiceName("Host Instances"), "biztalk_host_instances_total=0;;;0", "Self test OK. No WMI query was executed.");
|
||||
yield return BuildLine(CheckState.Ok, _options.ServiceName("Runtime Artifacts"), "biztalk_applications=0;;;0", "Self test OK. No WMI query was executed.");
|
||||
yield return BuildLine(CheckState.Ok, _options.ServiceName("Receive Locations"), "biztalk_receive_locations_total=0;;;0", "Self test OK. No WMI query was executed.");
|
||||
yield return BuildLine(CheckState.Ok, _options.ServiceName("Send Ports"), "biztalk_send_ports_total=0;;;0", "Self test OK. No WMI query was executed.");
|
||||
yield return BuildLine(CheckState.Ok, _options.ServiceName("Orchestrations"), "biztalk_orchestrations_total=0;;;0", "Self test OK. No WMI query was executed.");
|
||||
yield return BuildLine(CheckState.Ok, _options.ServiceName("Event Log"), "biztalk_eventlog_errors=0;;;0", "Self test OK. No event log was read.");
|
||||
}
|
||||
|
||||
@@ -79,7 +86,9 @@ namespace BizTalkCheckmkPulse
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("SQL Access"), "-", action);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Suspended Instances"), "-", action);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Host Instances"), "-", action);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Runtime Artifacts"), "-", action);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Receive Locations"), "-", action);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Send Ports"), "-", action);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Orchestrations"), "-", action);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Event Log"), "-", action);
|
||||
}
|
||||
|
||||
@@ -95,7 +104,9 @@ namespace BizTalkCheckmkPulse
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("SQL Access"), "-", detail);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Suspended Instances"), "-", detail);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Host Instances"), "-", detail);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Runtime Artifacts"), "-", detail);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Receive Locations"), "-", detail);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Send Ports"), "-", detail);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Orchestrations"), "-", detail);
|
||||
yield return BuildLine(CheckState.Unknown, _options.ServiceName("Event Log"), "-", detail);
|
||||
}
|
||||
|
||||
@@ -182,19 +193,22 @@ namespace BizTalkCheckmkPulse
|
||||
var total = result.SuspendedInstances.Count;
|
||||
var resumable = result.SuspendedInstances.Count(x => x.Kind == SuspendedKind.Resumable);
|
||||
var nonresumable = result.SuspendedInstances.Count(x => x.Kind == SuspendedKind.NonResumable);
|
||||
var state = DetermineSuspensionState(resumable, nonresumable);
|
||||
var routingFailureReports = result.SuspendedInstances.Count(x => x.IsRoutingFailureReport);
|
||||
var state = DetermineSuspensionState(resumable, nonresumable, routingFailureReports);
|
||||
var metrics = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"biztalk_suspended_total={0};;;0|biztalk_suspended_resumable={1};{2};;0|biztalk_suspended_nonresumable={3};;{4};0",
|
||||
"biztalk_suspended_total={0};;;0|biztalk_suspended_resumable={1};{2};;0|biztalk_suspended_nonresumable={3};;{4};0|biztalk_routing_failure_reports={5};;{6};0",
|
||||
total,
|
||||
resumable,
|
||||
_options.WarnResumableThreshold,
|
||||
nonresumable,
|
||||
_options.CritNonResumableThreshold);
|
||||
_options.CritNonResumableThreshold,
|
||||
routingFailureReports,
|
||||
_options.CritRoutingFailureThreshold);
|
||||
|
||||
var detail = total == 0
|
||||
? "No suspended BizTalk service instances found."
|
||||
: BuildSuspensionDetail(result.SuspendedInstances, total, resumable, nonresumable);
|
||||
? "Suspended total=0, resumable=0, nonresumable=0, routing_failure_reports=0."
|
||||
: BuildSuspensionDetail(result.SuspendedInstances, total, resumable, nonresumable, routingFailureReports);
|
||||
return BuildLine(state, _options.ServiceName("Suspended Instances"), metrics, detail);
|
||||
}
|
||||
|
||||
@@ -245,65 +259,147 @@ namespace BizTalkCheckmkPulse
|
||||
return BuildLine(state, _options.ServiceName("Host Instances"), metrics, detail.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formatiert aggregierte Receive-Location-, Send-Port- und Orchestration-Zustaende.
|
||||
/// </summary>
|
||||
/// <param name="result">Probe-Ergebnis.</param>
|
||||
/// <returns>Checkmk-Zeile fuer Runtime Artifacts.</returns>
|
||||
private string FormatRuntimeArtifacts(ProbeResult result)
|
||||
private string FormatReceiveLocations(ProbeResult result)
|
||||
{
|
||||
if (!result.Platform.RuntimeArtifactsDataAvailable)
|
||||
if (!result.Platform.ReceiveLocationsDataAvailable)
|
||||
{
|
||||
var errorDetail = "BizTalk Runtime Artifacts konnten nicht vollstaendig gelesen werden. Teilwerte werden nicht als OK gewertet.";
|
||||
return BuildLine(
|
||||
CheckState.Unknown,
|
||||
_options.ServiceName("Runtime Artifacts"),
|
||||
_options.ServiceName("Receive Locations"),
|
||||
"-",
|
||||
AppendDiagnostics(errorDetail, SelectDiagnostics(result, DiagnosticArea.Wmi, "WMI namespace connection", "MSBTS_ReceiveLocation", "MSBTS_SendPort", "MSBTS_Orchestration")));
|
||||
AppendDiagnostics(
|
||||
"Receive Locations konnten nicht verlaesslich gelesen werden.",
|
||||
SelectDiagnostics(result, DiagnosticArea.Wmi, "WMI namespace connection", "MSBTS_ReceiveLocation")));
|
||||
}
|
||||
|
||||
var receiveLocations = result.Applications.Sum(x => x.ReceiveLocationTotal);
|
||||
var receiveLocationsDisabled = result.Applications.Sum(x => x.ReceiveLocationDisabled);
|
||||
var sendPorts = result.Applications.Sum(x => x.SendPortTotal);
|
||||
var sendPortsStarted = result.Applications.Sum(x => x.SendPortStarted);
|
||||
var sendPortsInactive = result.Applications.Sum(x => x.SendPortStopped + x.SendPortBound);
|
||||
var sendPortsUnknown = result.Applications.Sum(x => x.SendPortUnknown);
|
||||
var orchestrations = result.Applications.Sum(x => x.OrchestrationTotal);
|
||||
var orchestrationsStarted = result.Applications.Sum(x => x.OrchestrationStarted);
|
||||
var orchestrationsInactive = result.Applications.Sum(x => x.OrchestrationStopped + x.OrchestrationBound + x.OrchestrationUnbound);
|
||||
var orchestrationsUnknown = result.Applications.Sum(x => x.OrchestrationUnknown);
|
||||
var state = sendPortsUnknown > 0 || orchestrationsUnknown > 0
|
||||
var disabled = result.ReceiveLocations.Where(x => x.IsDisabled == true).ToArray();
|
||||
var unknown = result.ReceiveLocations.Where(x => !x.IsDisabled.HasValue).ToArray();
|
||||
var expectedDisabled = disabled
|
||||
.Where(x => _options.IsExpectedDisabledReceiveLocation(x.ApplicationName, x.Name))
|
||||
.ToArray();
|
||||
var unexpectedDisabled = disabled.Except(expectedDisabled).ToArray();
|
||||
var enabled = result.ReceiveLocations.Count - disabled.Length - unknown.Length;
|
||||
var state = unknown.Length > 0
|
||||
? CheckState.Unknown
|
||||
: _options.AlertOnArtifactRuntimeIssues && unexpectedDisabled.Length > 0
|
||||
? CheckState.Critical
|
||||
: _options.AlertOnArtifactRuntimeIssues && (receiveLocationsDisabled > 0 || sendPortsInactive > 0 || orchestrationsInactive > 0)
|
||||
: CheckState.Ok;
|
||||
var metrics = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"biztalk_receive_locations_total={0};;;0|biztalk_receive_locations_enabled={1};;;0|biztalk_receive_locations_disabled={2};;;0|biztalk_receive_locations_unexpected_disabled={3};;1;0|biztalk_receive_locations_expected_disabled={4};;;0|biztalk_receive_locations_unknown={5};;1;0",
|
||||
result.ReceiveLocations.Count,
|
||||
enabled,
|
||||
disabled.Length,
|
||||
unexpectedDisabled.Length,
|
||||
expectedDisabled.Length,
|
||||
unknown.Length);
|
||||
var detail = new StringBuilder()
|
||||
.Append("Receive locations total=").Append(result.ReceiveLocations.Count)
|
||||
.Append(", enabled=").Append(enabled)
|
||||
.Append(", unexpected_disabled=").Append(unexpectedDisabled.Length)
|
||||
.Append(", expected_disabled=").Append(expectedDisabled.Length)
|
||||
.Append(", unknown=").Append(unknown.Length);
|
||||
AppendLimitedList(detail, "affected", unexpectedDisabled.Concat(unknown).Select(ReceiveLocationDisplay));
|
||||
return BuildLine(state, _options.ServiceName("Receive Locations"), metrics, detail.ToString());
|
||||
}
|
||||
|
||||
private string FormatSendPorts(ProbeResult result)
|
||||
{
|
||||
if (!result.Platform.SendPortsDataAvailable)
|
||||
{
|
||||
return BuildLine(
|
||||
CheckState.Unknown,
|
||||
_options.ServiceName("Send Ports"),
|
||||
"-",
|
||||
AppendDiagnostics(
|
||||
"Send Ports konnten nicht verlaesslich gelesen werden.",
|
||||
SelectDiagnostics(result, DiagnosticArea.Wmi, "WMI namespace connection", "MSBTS_SendPort")));
|
||||
}
|
||||
|
||||
var started = result.SendPorts.Count(x => x.Status == SendPortStarted);
|
||||
var stopped = result.SendPorts.Count(x => x.Status == SendPortStopped);
|
||||
var bound = result.SendPorts.Count(x => x.Status == SendPortBound);
|
||||
var unknown = result.SendPorts.Where(x => x.Status != SendPortStarted && x.Status != SendPortStopped && x.Status != SendPortBound).ToArray();
|
||||
var inactive = result.SendPorts.Where(x => x.Status == SendPortStopped || x.Status == SendPortBound).ToArray();
|
||||
var expectedInactive = inactive
|
||||
.Where(x => _options.IsExpectedInactiveSendPort(x.ApplicationName, x.Name))
|
||||
.ToArray();
|
||||
var unexpectedInactive = inactive.Except(expectedInactive).ToArray();
|
||||
var state = unknown.Length > 0 || (_options.AlertOnArtifactRuntimeIssues && unexpectedInactive.Length > 0)
|
||||
? CheckState.Critical
|
||||
: CheckState.Ok;
|
||||
var metrics = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"biztalk_send_ports_total={0};;;0|biztalk_send_ports_started={1};;;0|biztalk_send_ports_stopped={2};;;0|biztalk_send_ports_bound={3};;;0|biztalk_send_ports_unexpected_inactive={4};;1;0|biztalk_send_ports_expected_inactive={5};;;0|biztalk_send_ports_unknown={6};;1;0",
|
||||
result.SendPorts.Count,
|
||||
started,
|
||||
stopped,
|
||||
bound,
|
||||
unexpectedInactive.Length,
|
||||
expectedInactive.Length,
|
||||
unknown.Length);
|
||||
var detail = new StringBuilder()
|
||||
.Append("Send ports total=").Append(result.SendPorts.Count)
|
||||
.Append(", started=").Append(started)
|
||||
.Append(", stopped=").Append(stopped)
|
||||
.Append(", bound=").Append(bound)
|
||||
.Append(", unexpected_inactive=").Append(unexpectedInactive.Length)
|
||||
.Append(", expected_inactive=").Append(expectedInactive.Length)
|
||||
.Append(", unknown=").Append(unknown.Length);
|
||||
AppendLimitedList(detail, "affected", unexpectedInactive.Concat(unknown).Select(SendPortDisplay));
|
||||
return BuildLine(state, _options.ServiceName("Send Ports"), metrics, detail.ToString());
|
||||
}
|
||||
|
||||
private string FormatOrchestrations(ProbeResult result)
|
||||
{
|
||||
if (!result.Platform.OrchestrationsDataAvailable)
|
||||
{
|
||||
return BuildLine(
|
||||
CheckState.Unknown,
|
||||
_options.ServiceName("Orchestrations"),
|
||||
"-",
|
||||
AppendDiagnostics(
|
||||
"Orchestrations konnten nicht verlaesslich gelesen werden.",
|
||||
SelectDiagnostics(result, DiagnosticArea.Wmi, "WMI namespace connection", "MSBTS_Orchestration")));
|
||||
}
|
||||
|
||||
var total = result.Applications.Sum(x => x.OrchestrationTotal);
|
||||
var started = result.Applications.Sum(x => x.OrchestrationStarted);
|
||||
var stopped = result.Applications.Sum(x => x.OrchestrationStopped);
|
||||
var bound = result.Applications.Sum(x => x.OrchestrationBound);
|
||||
var unbound = result.Applications.Sum(x => x.OrchestrationUnbound);
|
||||
var unknown = result.Applications.Sum(x => x.OrchestrationUnknown);
|
||||
var inactive = stopped + bound + unbound;
|
||||
var state = unknown > 0
|
||||
? CheckState.Critical
|
||||
: _options.AlertOnInactiveOrchestrations && inactive > 0
|
||||
? CheckState.Warning
|
||||
: CheckState.Ok;
|
||||
var metrics = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"biztalk_applications={0};;;0|biztalk_receive_locations={1};;;0|biztalk_receive_locations_disabled={2};1;;0|biztalk_send_ports={3};;;0|biztalk_send_ports_started={4};;;0|biztalk_send_ports_inactive={5};1;;0|biztalk_send_ports_unknown={6};;1;0|biztalk_orchestrations={7};;;0|biztalk_orchestrations_started={8};;;0|biztalk_orchestrations_inactive={9};1;;0|biztalk_orchestrations_unknown={10};;1;0",
|
||||
result.Applications.Count,
|
||||
receiveLocations,
|
||||
receiveLocationsDisabled,
|
||||
sendPorts,
|
||||
sendPortsStarted,
|
||||
sendPortsInactive,
|
||||
sendPortsUnknown,
|
||||
orchestrations,
|
||||
orchestrationsStarted,
|
||||
orchestrationsInactive,
|
||||
orchestrationsUnknown);
|
||||
|
||||
var detail = new StringBuilder();
|
||||
detail.Append("Applications=").Append(result.Applications.Count)
|
||||
.Append("; receive_locations total=").Append(receiveLocations).Append(", disabled=").Append(receiveLocationsDisabled)
|
||||
.Append("; send_ports total=").Append(sendPorts).Append(", started=").Append(sendPortsStarted).Append(", inactive=").Append(sendPortsInactive).Append(", unknown=").Append(sendPortsUnknown)
|
||||
.Append("; orchestrations total=").Append(orchestrations).Append(", started=").Append(orchestrationsStarted).Append(", inactive=").Append(orchestrationsInactive).Append(", unknown=").Append(orchestrationsUnknown);
|
||||
|
||||
"biztalk_orchestrations_total={0};;;0|biztalk_orchestrations_started={1};;;0|biztalk_orchestrations_stopped={2};;;0|biztalk_orchestrations_bound={3};;;0|biztalk_orchestrations_unbound={4};;;0|biztalk_orchestrations_unknown={5};;1;0",
|
||||
total,
|
||||
started,
|
||||
stopped,
|
||||
bound,
|
||||
unbound,
|
||||
unknown);
|
||||
var detail = new StringBuilder()
|
||||
.Append("Orchestrations total=").Append(total)
|
||||
.Append(", started=").Append(started)
|
||||
.Append(", stopped=").Append(stopped)
|
||||
.Append(", bound=").Append(bound)
|
||||
.Append(", unbound=").Append(unbound)
|
||||
.Append(", unknown=").Append(unknown);
|
||||
var affected = result.Applications
|
||||
.Where(x => x.ReceiveLocationDisabled > 0 || x.SendPortStopped + x.SendPortBound + x.SendPortUnknown > 0 || x.OrchestrationStopped + x.OrchestrationBound + x.OrchestrationUnbound + x.OrchestrationUnknown > 0)
|
||||
.Take(_options.MaxSummaryItems)
|
||||
.Select(x => x.ApplicationName + "(rl_disabled=" + x.ReceiveLocationDisabled + ", sp_inactive=" + (x.SendPortStopped + x.SendPortBound) + ", orch_inactive=" + (x.OrchestrationStopped + x.OrchestrationBound + x.OrchestrationUnbound) + ")");
|
||||
AppendList(detail, "notable_apps", affected);
|
||||
return BuildLine(state, _options.ServiceName("Runtime Artifacts"), metrics, detail.ToString());
|
||||
.Where(x => x.OrchestrationStopped + x.OrchestrationBound + x.OrchestrationUnbound + x.OrchestrationUnknown > 0)
|
||||
.OrderByDescending(x => x.OrchestrationUnknown)
|
||||
.ThenByDescending(x => x.OrchestrationStopped + x.OrchestrationBound + x.OrchestrationUnbound)
|
||||
.Select(x => x.ApplicationName + "(inactive="
|
||||
+ (x.OrchestrationStopped + x.OrchestrationBound + x.OrchestrationUnbound)
|
||||
+ ",unknown=" + x.OrchestrationUnknown + ")");
|
||||
AppendLimitedList(detail, "affected_apps", affected);
|
||||
return BuildLine(state, _options.ServiceName("Orchestrations"), metrics, detail.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -362,16 +458,24 @@ namespace BizTalkCheckmkPulse
|
||||
{
|
||||
var resumable = group.Count(x => x.Kind == SuspendedKind.Resumable);
|
||||
var nonresumable = group.Count(x => x.Kind == SuspendedKind.NonResumable);
|
||||
var state = DetermineSuspensionState(resumable, nonresumable);
|
||||
var routingFailureReports = group.Count(x => x.IsRoutingFailureReport);
|
||||
var state = DetermineSuspensionState(resumable, nonresumable, routingFailureReports);
|
||||
var metrics = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"biztalk_suspended_total={0};;;0|biztalk_suspended_resumable={1};{2};;0|biztalk_suspended_nonresumable={3};;{4};0",
|
||||
"biztalk_suspended_total={0};;;0|biztalk_suspended_resumable={1};{2};;0|biztalk_suspended_nonresumable={3};;{4};0|biztalk_routing_failure_reports={5};;{6};0",
|
||||
group.Count(),
|
||||
resumable,
|
||||
_options.WarnResumableThreshold,
|
||||
nonresumable,
|
||||
_options.CritNonResumableThreshold);
|
||||
yield return BuildLine(state, _options.ServiceName("Suspended " + group.Key), metrics, "Suspended instances: resumable=" + resumable + ", nonresumable=" + nonresumable);
|
||||
_options.CritNonResumableThreshold,
|
||||
routingFailureReports,
|
||||
_options.CritRoutingFailureThreshold);
|
||||
yield return BuildLine(
|
||||
state,
|
||||
_options.ServiceName("Suspended " + group.Key),
|
||||
metrics,
|
||||
"Suspended total=" + group.Count() + ", resumable=" + resumable
|
||||
+ ", nonresumable=" + nonresumable + ", routing_failure_reports=" + routingFailureReports);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,8 +485,14 @@ namespace BizTalkCheckmkPulse
|
||||
/// <param name="resumable">Anzahl fortsetzbarer Instanzen.</param>
|
||||
/// <param name="nonresumable">Anzahl nicht fortsetzbarer Instanzen.</param>
|
||||
/// <returns>Zustand gemaess konfigurierten Schwellwerten.</returns>
|
||||
private CheckState DetermineSuspensionState(int resumable, int nonresumable)
|
||||
private CheckState DetermineSuspensionState(int resumable, int nonresumable, int routingFailureReports)
|
||||
{
|
||||
if (_options.CritRoutingFailureThreshold > 0
|
||||
&& routingFailureReports >= _options.CritRoutingFailureThreshold)
|
||||
{
|
||||
return CheckState.Critical;
|
||||
}
|
||||
|
||||
if (_options.CritNonResumableThreshold > 0 && nonresumable >= _options.CritNonResumableThreshold)
|
||||
{
|
||||
return CheckState.Critical;
|
||||
@@ -404,24 +514,32 @@ namespace BizTalkCheckmkPulse
|
||||
/// <param name="resumable">Anzahl fortsetzbarer Instanzen.</param>
|
||||
/// <param name="nonresumable">Anzahl nicht fortsetzbarer Instanzen.</param>
|
||||
/// <returns>Kompakter Detailtext.</returns>
|
||||
private string BuildSuspensionDetail(IEnumerable<SuspendedInstance> instances, int total, int resumable, int nonresumable)
|
||||
private string BuildSuspensionDetail(
|
||||
IEnumerable<SuspendedInstance> instances,
|
||||
int total,
|
||||
int resumable,
|
||||
int nonresumable,
|
||||
int routingFailureReports)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append(total).Append(" suspended BizTalk service instance(s): resumable=").Append(resumable)
|
||||
.Append(", nonresumable=").Append(nonresumable);
|
||||
builder.Append("Suspended total=").Append(total)
|
||||
.Append(", resumable=").Append(resumable)
|
||||
.Append(", nonresumable=").Append(nonresumable)
|
||||
.Append(", routing_failure_reports=").Append(routingFailureReports);
|
||||
|
||||
var apps = instances
|
||||
.Where(x => !x.IsRoutingFailureReport
|
||||
&& !string.Equals(x.ApplicationName, "(unknown)", StringComparison.OrdinalIgnoreCase))
|
||||
.GroupBy(x => x.ApplicationName)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(_options.MaxSummaryItems)
|
||||
.Select(x => x.Key + "(R=" + x.Count(y => y.Kind == SuspendedKind.Resumable) + ",NR=" + x.Count(y => y.Kind == SuspendedKind.NonResumable) + ")");
|
||||
AppendList(builder, "applications", apps);
|
||||
AppendLimitedList(builder, "applications", apps);
|
||||
|
||||
var examples = instances
|
||||
.Where(x => !x.IsRoutingFailureReport)
|
||||
.OrderByDescending(x => x.SuspendTime ?? DateTime.MinValue)
|
||||
.Take(Math.Min(_options.MaxSummaryItems, 5))
|
||||
.Select(x => EmptyAsUnknown(x.ServiceName) + " on " + EmptyAsUnknown(x.HostName));
|
||||
AppendList(builder, "examples", examples);
|
||||
.Select(x => EmptyAsUnknown(x.ServiceName) + "@" + EmptyAsUnknown(x.HostName));
|
||||
AppendLimitedList(builder, "recent", examples);
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
@@ -433,13 +551,20 @@ namespace BizTalkCheckmkPulse
|
||||
/// <param name="metrics">Performance-Daten oder Bindestrich.</param>
|
||||
/// <param name="detail">Menschenlesbare Service-Ausgabe.</param>
|
||||
/// <returns>Vollstaendige Local-Check-Zeile.</returns>
|
||||
private static string BuildLine(CheckState state, string serviceName, string metrics, string detail)
|
||||
private string BuildLine(CheckState state, string serviceName, string metrics, string detail)
|
||||
{
|
||||
var sanitizedDetail = SanitizeDetail(detail);
|
||||
if (sanitizedDetail.Length > _options.MaxDetailCharacters)
|
||||
{
|
||||
sanitizedDetail = sanitizedDetail.Substring(0, _options.MaxDetailCharacters - 16).TrimEnd()
|
||||
+ "... [truncated]";
|
||||
}
|
||||
|
||||
return ((int)state).ToString(CultureInfo.InvariantCulture)
|
||||
+ " \"" + SanitizeService(serviceName) + "\" "
|
||||
+ (string.IsNullOrWhiteSpace(metrics) ? "-" : metrics)
|
||||
+ " "
|
||||
+ SanitizeDetail(detail);
|
||||
+ sanitizedDetail;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -489,6 +614,57 @@ namespace BizTalkCheckmkPulse
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendLimitedList(StringBuilder builder, string label, IEnumerable<string> values)
|
||||
{
|
||||
var all = values.Where(x => !string.IsNullOrWhiteSpace(x)).ToArray();
|
||||
if (all.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var visible = all.Take(_options.MaxSummaryItems).ToArray();
|
||||
builder.Append("; ").Append(label).Append("=").Append(string.Join(", ", visible));
|
||||
if (all.Length > visible.Length)
|
||||
{
|
||||
builder.Append(" (+").Append(all.Length - visible.Length).Append(" more)");
|
||||
}
|
||||
}
|
||||
|
||||
private static string ReceiveLocationDisplay(ReceiveLocationState item)
|
||||
{
|
||||
return ArtifactDisplay(item.ApplicationName, item.Name);
|
||||
}
|
||||
|
||||
private static string SendPortDisplay(SendPortState item)
|
||||
{
|
||||
return ArtifactDisplay(item.ApplicationName, item.Name)
|
||||
+ "(" + SendPortStateName(item.Status) + ")";
|
||||
}
|
||||
|
||||
private static string ArtifactDisplay(string applicationName, string artifactName)
|
||||
{
|
||||
var application = EmptyAsUnknown(applicationName);
|
||||
var name = EmptyAsUnknown(artifactName);
|
||||
return string.Equals(application, "(unknown)", StringComparison.OrdinalIgnoreCase)
|
||||
? name
|
||||
: application + "\\" + name;
|
||||
}
|
||||
|
||||
private static string SendPortStateName(int status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case SendPortStarted:
|
||||
return "started";
|
||||
case SendPortStopped:
|
||||
return "stopped";
|
||||
case SendPortBound:
|
||||
return "bound";
|
||||
default:
|
||||
return "unknown:" + status.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Haengt einen optionalen benannten Wert an einen Detailtext an.
|
||||
/// </summary>
|
||||
|
||||
@@ -96,6 +96,8 @@ namespace BizTalkCheckmkPulse
|
||||
Platform = new PlatformState();
|
||||
HostInstances = new List<HostInstanceState>();
|
||||
SuspendedInstances = new List<SuspendedInstance>();
|
||||
ReceiveLocations = new List<ReceiveLocationState>();
|
||||
SendPorts = new List<SendPortState>();
|
||||
Applications = new List<ApplicationRuntimeState>();
|
||||
SqlTargets = new List<SqlAccessState>();
|
||||
EventLog = new EventLogState();
|
||||
@@ -105,6 +107,8 @@ namespace BizTalkCheckmkPulse
|
||||
public PlatformState Platform { get; private set; }
|
||||
public List<HostInstanceState> HostInstances { get; private set; }
|
||||
public List<SuspendedInstance> SuspendedInstances { get; private set; }
|
||||
public List<ReceiveLocationState> ReceiveLocations { get; private set; }
|
||||
public List<SendPortState> SendPorts { get; private set; }
|
||||
public List<ApplicationRuntimeState> Applications { get; private set; }
|
||||
public List<SqlAccessState> SqlTargets { get; private set; }
|
||||
public string ExecutionIdentity { get; set; }
|
||||
@@ -121,7 +125,9 @@ namespace BizTalkCheckmkPulse
|
||||
public bool PlatformDataAvailable { get; set; }
|
||||
public bool HostInstancesDataAvailable { get; set; }
|
||||
public bool SuspendedInstancesDataAvailable { get; set; }
|
||||
public bool RuntimeArtifactsDataAvailable { get; set; }
|
||||
public bool ReceiveLocationsDataAvailable { get; set; }
|
||||
public bool SendPortsDataAvailable { get; set; }
|
||||
public bool OrchestrationsDataAvailable { get; set; }
|
||||
public string ServerName { get; set; }
|
||||
public string GroupName { get; set; }
|
||||
public string OperatorGroup { get; set; }
|
||||
@@ -169,7 +175,33 @@ namespace BizTalkCheckmkPulse
|
||||
public string InstanceId { get; set; }
|
||||
public string ErrorDescription { get; set; }
|
||||
public DateTime? SuspendTime { get; set; }
|
||||
public int ServiceClassId { get; set; }
|
||||
public SuspendedKind Kind { get; set; }
|
||||
|
||||
public bool IsRoutingFailureReport
|
||||
{
|
||||
get { return ServiceClassId == 64; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Konfigurations- und Laufzeitzustand einer Receive Location.
|
||||
/// </summary>
|
||||
internal sealed class ReceiveLocationState
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string ApplicationName { get; set; }
|
||||
public bool? IsDisabled { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Laufzeitzustand eines Send Ports.
|
||||
/// </summary>
|
||||
internal sealed class SendPortState
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string ApplicationName { get; set; }
|
||||
public int Status { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -20,8 +20,13 @@ namespace BizTalkCheckmkPulse
|
||||
public int SqlConnectionTimeoutSeconds { get; set; }
|
||||
public int WarnResumableThreshold { get; set; }
|
||||
public int CritNonResumableThreshold { get; set; }
|
||||
public int CritRoutingFailureThreshold { get; set; }
|
||||
public int MaxSummaryItems { get; set; }
|
||||
public int MaxDetailCharacters { get; set; }
|
||||
public bool AlertOnArtifactRuntimeIssues { get; set; }
|
||||
public bool AlertOnInactiveOrchestrations { get; set; }
|
||||
public IReadOnlyList<string> ExpectedDisabledReceiveLocations { get; set; }
|
||||
public IReadOnlyList<string> ExpectedInactiveSendPorts { get; set; }
|
||||
public bool EmitPerApplicationSuspensionServices { get; set; }
|
||||
public bool ProbeEventLog { get; set; }
|
||||
public int EventLogLookbackMinutes { get; set; }
|
||||
@@ -49,8 +54,13 @@ namespace BizTalkCheckmkPulse
|
||||
SqlConnectionTimeoutSeconds = 5;
|
||||
WarnResumableThreshold = 1;
|
||||
CritNonResumableThreshold = 1;
|
||||
MaxSummaryItems = 12;
|
||||
AlertOnArtifactRuntimeIssues = false;
|
||||
CritRoutingFailureThreshold = 1;
|
||||
MaxSummaryItems = 5;
|
||||
MaxDetailCharacters = 1600;
|
||||
AlertOnArtifactRuntimeIssues = true;
|
||||
AlertOnInactiveOrchestrations = false;
|
||||
ExpectedDisabledReceiveLocations = new string[0];
|
||||
ExpectedInactiveSendPorts = new string[0];
|
||||
EmitPerApplicationSuspensionServices = false;
|
||||
ProbeEventLog = true;
|
||||
EventLogLookbackMinutes = 60;
|
||||
@@ -96,8 +106,13 @@ namespace BizTalkCheckmkPulse
|
||||
options.SqlConnectionTimeoutSeconds = ReadInt(settings, "SqlConnectionTimeoutSeconds", options.SqlConnectionTimeoutSeconds, 3, 60);
|
||||
options.WarnResumableThreshold = ReadInt(settings, "WarnResumableThreshold", options.WarnResumableThreshold, 0, 1000000);
|
||||
options.CritNonResumableThreshold = ReadInt(settings, "CritNonResumableThreshold", options.CritNonResumableThreshold, 0, 1000000);
|
||||
options.CritRoutingFailureThreshold = ReadInt(settings, "CritRoutingFailureThreshold", options.CritRoutingFailureThreshold, 0, 1000000);
|
||||
options.MaxSummaryItems = ReadInt(settings, "MaxSummaryItems", options.MaxSummaryItems, 1, 100);
|
||||
options.MaxDetailCharacters = ReadInt(settings, "MaxDetailCharacters", options.MaxDetailCharacters, 256, 8192);
|
||||
options.AlertOnArtifactRuntimeIssues = ReadBool(settings, "AlertOnArtifactRuntimeIssues", options.AlertOnArtifactRuntimeIssues);
|
||||
options.AlertOnInactiveOrchestrations = ReadBool(settings, "AlertOnInactiveOrchestrations", options.AlertOnInactiveOrchestrations);
|
||||
options.ExpectedDisabledReceiveLocations = ReadExactList(ReadString(settings, "ExpectedDisabledReceiveLocations", string.Empty));
|
||||
options.ExpectedInactiveSendPorts = ReadExactList(ReadString(settings, "ExpectedInactiveSendPorts", string.Empty));
|
||||
options.EmitPerApplicationSuspensionServices = ReadBool(settings, "EmitPerApplicationSuspensionServices", options.EmitPerApplicationSuspensionServices);
|
||||
options.ProbeEventLog = ReadBool(settings, "ProbeEventLog", options.ProbeEventLog);
|
||||
options.EventLogLookbackMinutes = ReadInt(settings, "EventLogLookbackMinutes", options.EventLogLookbackMinutes, 1, 10080);
|
||||
@@ -245,6 +260,49 @@ namespace BizTalkCheckmkPulse
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Liest eine Pipe-getrennte, exakte Allowlist. Wildcards werden bewusst nicht interpretiert.
|
||||
/// </summary>
|
||||
private static IReadOnlyList<string> ReadExactList(string value)
|
||||
{
|
||||
return (value ?? string.Empty)
|
||||
.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x => x.Trim())
|
||||
.Where(x => x.Length > 0)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
internal bool IsExpectedDisabledReceiveLocation(string applicationName, string artifactName)
|
||||
{
|
||||
return MatchesArtifact(ExpectedDisabledReceiveLocations, applicationName, artifactName);
|
||||
}
|
||||
|
||||
internal bool IsExpectedInactiveSendPort(string applicationName, string artifactName)
|
||||
{
|
||||
return MatchesArtifact(ExpectedInactiveSendPorts, applicationName, artifactName);
|
||||
}
|
||||
|
||||
private static bool MatchesArtifact(
|
||||
IEnumerable<string> configuredEntries,
|
||||
string applicationName,
|
||||
string artifactName)
|
||||
{
|
||||
var name = (artifactName ?? string.Empty).Trim();
|
||||
var application = (applicationName ?? string.Empty).Trim();
|
||||
if (name.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var qualified = application.Length == 0 || string.Equals(application, "(unknown)", StringComparison.OrdinalIgnoreCase)
|
||||
? string.Empty
|
||||
: application + "\\" + name;
|
||||
return configuredEntries.Any(x =>
|
||||
string.Equals(x, name, StringComparison.OrdinalIgnoreCase)
|
||||
|| (qualified.Length > 0 && string.Equals(x, qualified, StringComparison.OrdinalIgnoreCase)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prueft einen Wert ohne Beachtung der Gross-/Kleinschreibung gegen Kandidaten.
|
||||
/// </summary>
|
||||
|
||||
@@ -70,6 +70,11 @@ namespace BizTalkCheckmkPulse
|
||||
{
|
||||
logger.Info("Collection started. snapshot=" + options.SnapshotPath);
|
||||
var result = Collect(options);
|
||||
foreach (var diagnostic in result.Diagnostics)
|
||||
{
|
||||
logger.Warning("Probe diagnostic: " + diagnostic.ToDisplayText());
|
||||
}
|
||||
|
||||
var lines = formatter.Format(result).ToArray();
|
||||
new SnapshotStore(options.SnapshotPath, options.SnapshotMaxBytes)
|
||||
.Write(lines, DateTime.UtcNow, CurrentIdentity());
|
||||
@@ -79,6 +84,20 @@ namespace BizTalkCheckmkPulse
|
||||
+ lines.Length
|
||||
+ " diagnostics="
|
||||
+ result.Diagnostics.Count
|
||||
+ " suspended_total="
|
||||
+ result.SuspendedInstances.Count
|
||||
+ " routing_failure_reports="
|
||||
+ result.SuspendedInstances.Count(x => x.IsRoutingFailureReport)
|
||||
+ " receive_locations_total="
|
||||
+ result.ReceiveLocations.Count
|
||||
+ " receive_locations_disabled="
|
||||
+ result.ReceiveLocations.Count(x => x.IsDisabled == true)
|
||||
+ " receive_locations_unknown="
|
||||
+ result.ReceiveLocations.Count(x => !x.IsDisabled.HasValue)
|
||||
+ " send_ports_total="
|
||||
+ result.SendPorts.Count
|
||||
+ " send_ports_not_started="
|
||||
+ result.SendPorts.Count(x => x.Status != 3)
|
||||
+ " elapsed_ms="
|
||||
+ stopwatch.ElapsedMilliseconds);
|
||||
return 0;
|
||||
|
||||
@@ -6,5 +6,5 @@ using System.Reflection;
|
||||
[assembly: AssemblyDescription("Privileged BizTalk data provider and validated Checkmk snapshot consumer")]
|
||||
[assembly: AssemblyCompany("BEW")]
|
||||
[assembly: AssemblyProduct("BizTalk Checkmk Pulse")]
|
||||
[assembly: AssemblyVersion("2.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("2.0.0.0")]
|
||||
[assembly: AssemblyVersion("2.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("2.1.0.0")]
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace BizTalkCheckmkPulse
|
||||
/// </summary>
|
||||
internal sealed class SnapshotStore
|
||||
{
|
||||
internal const string Magic = "BIZTALK_CHECKMK_PULSE_SNAPSHOT_V1";
|
||||
internal const string Magic = "BIZTALK_CHECKMK_PULSE_SNAPSHOT_V2";
|
||||
private static readonly UTF8Encoding StrictUtf8 = new UTF8Encoding(false, true);
|
||||
private readonly string _path;
|
||||
private readonly int _maxBytes;
|
||||
@@ -258,9 +258,9 @@ namespace BizTalkCheckmkPulse
|
||||
}
|
||||
}
|
||||
|
||||
if (count < 6)
|
||||
if (count < 8)
|
||||
{
|
||||
throw new InvalidDataException("Snapshot must contain all six stable services.");
|
||||
throw new InvalidDataException("Snapshot must contain all eight stable services.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace BizTalkCheckmkPulse
|
||||
private const int EAccessDenied = unchecked((int)0x80070005);
|
||||
internal const string GroupSettingQuery =
|
||||
"SELECT Name, BizTalkOperatorGroup, BizTalkReadOnlyUserGroup, MgmtDbServerName, MgmtDbName, SubscriptionDBServerName, SubscriptionDBName FROM MSBTS_GroupSetting";
|
||||
internal const string SuspendedInstancesQuery =
|
||||
"SELECT * FROM MSBTS_ServiceInstance WHERE ServiceStatus = 4 OR ServiceStatus = 32 OR ServiceClass = 64";
|
||||
private readonly MonitoringOptions _options;
|
||||
|
||||
/// <summary>
|
||||
@@ -58,7 +60,7 @@ namespace BizTalkCheckmkPulse
|
||||
result.Platform.PlatformDataAvailable = QueryPlatform(scope, result);
|
||||
result.Platform.HostInstancesDataAvailable = QueryHostInstances(scope, result, server);
|
||||
var applicationIndex = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
result.Platform.RuntimeArtifactsDataAvailable = QueryApplicationRuntime(scope, result, applicationIndex);
|
||||
QueryApplicationRuntime(scope, result, applicationIndex);
|
||||
if (_options.EmitPerApplicationSuspensionServices)
|
||||
{
|
||||
AddArtifactIndex(scope, result, applicationIndex, "MSBTS_ReceivePort");
|
||||
@@ -196,31 +198,52 @@ namespace BizTalkCheckmkPulse
|
||||
/// <param name="scope">Verbundener BizTalk-WMI-Scope.</param>
|
||||
/// <param name="result">Zu aktualisierendes Ergebnisobjekt.</param>
|
||||
/// <param name="applicationIndex">Best-Effort-Index fuer Suspensionsdetails.</param>
|
||||
/// <returns><c>true</c>, wenn alle drei Pflichtabfragen erfolgreich waren.</returns>
|
||||
private bool QueryApplicationRuntime(
|
||||
private void QueryApplicationRuntime(
|
||||
ManagementScope scope,
|
||||
ProbeResult result,
|
||||
Dictionary<string, string> applicationIndex)
|
||||
{
|
||||
var apps = new Dictionary<string, ApplicationRuntimeState>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var receiveLocationsAvailable = TryQuery(scope, result, "MSBTS_ReceiveLocation", "SELECT * FROM MSBTS_ReceiveLocation", item =>
|
||||
result.Platform.ReceiveLocationsDataAvailable = TryQuery(scope, result, "MSBTS_ReceiveLocation", "SELECT * FROM MSBTS_ReceiveLocation", item =>
|
||||
{
|
||||
AddArtifactIndexEntry(applicationIndex, item);
|
||||
var app = GetApplication(apps, GetApplicationName(item));
|
||||
var applicationName = GetApplicationName(item);
|
||||
var name = FirstNonEmpty(WmiHelpers.GetString(item, "Name"), WmiHelpers.GetString(item, "ReceivePortName")) ?? "(unknown)";
|
||||
bool parsedIsDisabled;
|
||||
var isDisabledText = WmiHelpers.GetString(item, "IsDisabled");
|
||||
var isDisabled = bool.TryParse(isDisabledText, out parsedIsDisabled)
|
||||
? (bool?)parsedIsDisabled
|
||||
: null;
|
||||
result.ReceiveLocations.Add(new ReceiveLocationState
|
||||
{
|
||||
Name = name,
|
||||
ApplicationName = applicationName,
|
||||
IsDisabled = isDisabled
|
||||
});
|
||||
var app = GetApplication(apps, applicationName);
|
||||
app.ReceiveLocationTotal++;
|
||||
if (WmiHelpers.GetBoolean(item, "IsDisabled", false))
|
||||
if (isDisabled == true)
|
||||
{
|
||||
app.ReceiveLocationDisabled++;
|
||||
}
|
||||
}, true);
|
||||
|
||||
var sendPortsAvailable = TryQuery(scope, result, "MSBTS_SendPort", "SELECT * FROM MSBTS_SendPort", item =>
|
||||
result.Platform.SendPortsDataAvailable = TryQuery(scope, result, "MSBTS_SendPort", "SELECT * FROM MSBTS_SendPort", item =>
|
||||
{
|
||||
AddArtifactIndexEntry(applicationIndex, item);
|
||||
var app = GetApplication(apps, GetApplicationName(item));
|
||||
var applicationName = GetApplicationName(item);
|
||||
var name = WmiHelpers.GetString(item, "Name");
|
||||
var status = WmiHelpers.GetInt32(item, "Status", 0);
|
||||
result.SendPorts.Add(new SendPortState
|
||||
{
|
||||
Name = string.IsNullOrWhiteSpace(name) ? "(unknown)" : name,
|
||||
ApplicationName = applicationName,
|
||||
Status = status
|
||||
});
|
||||
var app = GetApplication(apps, applicationName);
|
||||
app.SendPortTotal++;
|
||||
switch (WmiHelpers.GetInt32(item, "Status", 0))
|
||||
switch (status)
|
||||
{
|
||||
case SendPortStarted:
|
||||
app.SendPortStarted++;
|
||||
@@ -237,7 +260,7 @@ namespace BizTalkCheckmkPulse
|
||||
}
|
||||
}, true);
|
||||
|
||||
var orchestrationsAvailable = TryQuery(scope, result, "MSBTS_Orchestration", "SELECT * FROM MSBTS_Orchestration", item =>
|
||||
result.Platform.OrchestrationsDataAvailable = TryQuery(scope, result, "MSBTS_Orchestration", "SELECT * FROM MSBTS_Orchestration", item =>
|
||||
{
|
||||
AddArtifactIndexEntry(applicationIndex, item);
|
||||
var app = GetApplication(apps, GetApplicationName(item));
|
||||
@@ -263,7 +286,6 @@ namespace BizTalkCheckmkPulse
|
||||
}, true);
|
||||
|
||||
result.Applications.AddRange(apps.Values.OrderBy(x => x.ApplicationName, StringComparer.OrdinalIgnoreCase));
|
||||
return receiveLocationsAvailable && sendPortsAvailable && orchestrationsAvailable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -275,9 +297,10 @@ namespace BizTalkCheckmkPulse
|
||||
/// <returns><c>true</c>, wenn die Pflichtabfrage erfolgreich war.</returns>
|
||||
private bool QuerySuspendedInstances(ManagementScope scope, ProbeResult result, Dictionary<string, string> applicationIndex)
|
||||
{
|
||||
return TryQuery(scope, result, "MSBTS_ServiceInstance", "SELECT * FROM MSBTS_ServiceInstance WHERE ServiceStatus = 4 OR ServiceStatus = 32", item =>
|
||||
return TryQuery(scope, result, "MSBTS_ServiceInstance", SuspendedInstancesQuery, item =>
|
||||
{
|
||||
var serviceStatus = WmiHelpers.GetInt32(item, "ServiceStatus", 0);
|
||||
var serviceClass = WmiHelpers.GetInt32(item, "ServiceClass", 0);
|
||||
result.SuspendedInstances.Add(new SuspendedInstance
|
||||
{
|
||||
ApplicationName = ResolveApplication(item, applicationIndex),
|
||||
@@ -287,7 +310,10 @@ namespace BizTalkCheckmkPulse
|
||||
InstanceId = WmiHelpers.GetString(item, "InstanceID"),
|
||||
ErrorDescription = WmiHelpers.GetString(item, "ErrorDescription"),
|
||||
SuspendTime = WmiHelpers.GetDmtfDateTime(item, "SuspendTime"),
|
||||
Kind = serviceStatus == SuspendedNonResumable ? SuspendedKind.NonResumable : SuspendedKind.Resumable
|
||||
ServiceClassId = serviceClass,
|
||||
Kind = serviceStatus == SuspendedNonResumable || serviceClass == 64
|
||||
? SuspendedKind.NonResumable
|
||||
: SuspendedKind.Resumable
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,11 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
Run("ProviderSqlLoginFailureIsPermission", ProviderSqlLoginFailureIsPermission);
|
||||
Run("RejectedSqlPrincipalIsExtracted", RejectedSqlPrincipalIsExtracted);
|
||||
Run("PlatformPermissionPropagatesToSqlDiscovery", PlatformPermissionPropagatesToSqlDiscovery);
|
||||
Run("RoutingFailureReportsAreCounted", RoutingFailureReportsAreCounted);
|
||||
Run("ReceiveLocationAllowlistSeparatesExpectedState", ReceiveLocationAllowlistSeparatesExpectedState);
|
||||
Run("UnknownReceiveLocationStateIsNotGreen", UnknownReceiveLocationStateIsNotGreen);
|
||||
Run("SendPortAllowlistSeparatesExpectedState", SendPortAllowlistSeparatesExpectedState);
|
||||
Run("ArtifactSummaryIsBounded", ArtifactSummaryIsBounded);
|
||||
Run("SnapshotRoundTripPreservesLines", SnapshotRoundTripPreservesLines);
|
||||
Run("SnapshotRejectsTampering", SnapshotRejectsTampering);
|
||||
Run("SnapshotRejectsStaleData", SnapshotRejectsStaleData);
|
||||
@@ -47,16 +52,19 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
private static void SelfTestEmitsAllStableServices()
|
||||
{
|
||||
var lines = new CheckmkLocalFormatter(new MonitoringOptions()).FormatSelfTest().ToArray();
|
||||
AssertEqual(6, lines.Length, "self-test line count");
|
||||
AssertEqual(6, lines.Distinct(StringComparer.Ordinal).Count(), "unique self-test lines");
|
||||
AssertEqual(8, lines.Length, "self-test line count");
|
||||
AssertEqual(8, lines.Distinct(StringComparer.Ordinal).Count(), "unique self-test lines");
|
||||
Assert(lines.All(x => x.StartsWith("0 \"BizTalk ", StringComparison.Ordinal)), "every self-test line must be OK");
|
||||
Assert(lines.Any(x => x.Contains("\"BizTalk Event Log\"")), "Event Log service missing");
|
||||
Assert(lines.Any(x => x.Contains("\"BizTalk Receive Locations\"")), "Receive Locations service missing");
|
||||
Assert(lines.Any(x => x.Contains("\"BizTalk Send Ports\"")), "Send Ports service missing");
|
||||
Assert(lines.Any(x => x.Contains("\"BizTalk Orchestrations\"")), "Orchestrations service missing");
|
||||
}
|
||||
|
||||
private static void UnavailableSourcesAreUnknown()
|
||||
{
|
||||
var lines = new CheckmkLocalFormatter(new MonitoringOptions()).Format(new ProbeResult()).Take(6).ToArray();
|
||||
AssertEqual(6, lines.Length, "stable service count");
|
||||
var lines = new CheckmkLocalFormatter(new MonitoringOptions()).Format(new ProbeResult()).Take(8).ToArray();
|
||||
AssertEqual(8, lines.Length, "stable service count");
|
||||
Assert(lines.All(x => x.StartsWith("3 \"BizTalk ", StringComparison.Ordinal)), "unavailable sources must be UNKNOWN");
|
||||
}
|
||||
|
||||
@@ -65,7 +73,7 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
var options = new MonitoringOptions { EmitPerApplicationSuspensionServices = true };
|
||||
var result = CreateSuspensionResult("(unknown)");
|
||||
var lines = new CheckmkLocalFormatter(options).Format(result).ToArray();
|
||||
AssertEqual(6, lines.Length, "unknown application must not create a dynamic service");
|
||||
AssertEqual(8, lines.Length, "unknown application must not create a dynamic service");
|
||||
}
|
||||
|
||||
private static void KnownApplicationCreatesService()
|
||||
@@ -73,7 +81,7 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
var options = new MonitoringOptions { EmitPerApplicationSuspensionServices = true };
|
||||
var result = CreateSuspensionResult("Orders");
|
||||
var lines = new CheckmkLocalFormatter(options).Format(result).ToArray();
|
||||
AssertEqual(7, lines.Length, "known application should create one dynamic service");
|
||||
AssertEqual(9, lines.Length, "known application should create one dynamic service");
|
||||
Assert(lines.Any(x => x.Contains("\"BizTalk Suspended Orders\"")), "known application service missing");
|
||||
}
|
||||
|
||||
@@ -93,6 +101,7 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
Assert(query.Contains("SubscriptionDBServerName"), "master MessageBox server property missing");
|
||||
Assert(query.Contains("SubscriptionDBName"), "master MessageBox database property missing");
|
||||
Assert(query.IndexOf("MessageBoxSetting", StringComparison.OrdinalIgnoreCase) < 0, "unsupported MessageBoxSetting class present");
|
||||
Assert(WmiBizTalkProbe.SuspendedInstancesQuery.Contains("ServiceClass = 64"), "routing failure report filter missing");
|
||||
}
|
||||
|
||||
private static void ProviderSqlLoginFailureIsPermission()
|
||||
@@ -137,6 +146,167 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
"SQL discovery classification");
|
||||
}
|
||||
|
||||
private static void RoutingFailureReportsAreCounted()
|
||||
{
|
||||
var result = new ProbeResult();
|
||||
result.Platform.SuspendedInstancesDataAvailable = true;
|
||||
result.SuspendedInstances.Add(new SuspendedInstance
|
||||
{
|
||||
ApplicationName = "(unknown)",
|
||||
ServiceName = string.Empty,
|
||||
ServiceClassId = 64,
|
||||
Kind = SuspendedKind.NonResumable
|
||||
});
|
||||
result.SuspendedInstances.Add(new SuspendedInstance
|
||||
{
|
||||
ApplicationName = "Orders",
|
||||
ServiceName = "Receive.Order",
|
||||
Kind = SuspendedKind.Resumable
|
||||
});
|
||||
|
||||
var line = FindServiceLine(result, "Suspended Instances");
|
||||
Assert(line.StartsWith("2 \"BizTalk Suspended Instances\"", StringComparison.Ordinal), "routing failure must be CRIT");
|
||||
Assert(line.Contains("biztalk_suspended_total=2"), "suspended total metric missing");
|
||||
Assert(line.Contains("biztalk_suspended_nonresumable=1"), "non-resumable metric missing");
|
||||
Assert(line.Contains("biztalk_routing_failure_reports=1"), "routing failure metric missing");
|
||||
Assert(line.Contains("routing_failure_reports=1"), "routing failure summary missing");
|
||||
}
|
||||
|
||||
private static void ReceiveLocationAllowlistSeparatesExpectedState()
|
||||
{
|
||||
var options = new MonitoringOptions
|
||||
{
|
||||
ExpectedDisabledReceiveLocations = new[] { "Maintenance\\RL Expected" }
|
||||
};
|
||||
var result = new ProbeResult();
|
||||
result.Platform.ReceiveLocationsDataAvailable = true;
|
||||
result.ReceiveLocations.Add(new ReceiveLocationState
|
||||
{
|
||||
ApplicationName = "Maintenance",
|
||||
Name = "RL Expected",
|
||||
IsDisabled = true
|
||||
});
|
||||
result.ReceiveLocations.Add(new ReceiveLocationState
|
||||
{
|
||||
ApplicationName = "Orders",
|
||||
Name = "RL Orders",
|
||||
IsDisabled = true
|
||||
});
|
||||
result.ReceiveLocations.Add(new ReceiveLocationState
|
||||
{
|
||||
ApplicationName = "Orders",
|
||||
Name = "RL Active",
|
||||
IsDisabled = false
|
||||
});
|
||||
|
||||
var line = FindServiceLine(result, "Receive Locations", options);
|
||||
Assert(line.StartsWith("2 \"BizTalk Receive Locations\"", StringComparison.Ordinal), "unexpected disabled receive location must be CRIT");
|
||||
Assert(line.Contains("biztalk_receive_locations_enabled=1"), "enabled receive metric missing");
|
||||
Assert(line.Contains("biztalk_receive_locations_unexpected_disabled=1"), "unexpected disabled metric missing");
|
||||
Assert(line.Contains("biztalk_receive_locations_expected_disabled=1"), "expected disabled metric missing");
|
||||
Assert(line.Contains(@"Orders\RL Orders"), "affected receive location missing");
|
||||
Assert(line.IndexOf("RL Expected", StringComparison.Ordinal) < 0, "expected disabled receive location should not clutter affected list");
|
||||
|
||||
options.ExpectedDisabledReceiveLocations = new[] { "Maintenance\\RL Expected", "RL Orders" };
|
||||
var allExpected = FindServiceLine(result, "Receive Locations", options);
|
||||
Assert(allExpected.StartsWith("0 \"BizTalk Receive Locations\"", StringComparison.Ordinal), "all expected disabled receive locations should be OK");
|
||||
Assert(allExpected.Contains("biztalk_receive_locations_expected_disabled=2"), "all expected receive count missing");
|
||||
}
|
||||
|
||||
private static void SendPortAllowlistSeparatesExpectedState()
|
||||
{
|
||||
var options = new MonitoringOptions
|
||||
{
|
||||
ExpectedInactiveSendPorts = new[] { "Maintenance\\SP Expected" }
|
||||
};
|
||||
var result = new ProbeResult();
|
||||
result.Platform.SendPortsDataAvailable = true;
|
||||
result.SendPorts.Add(new SendPortState
|
||||
{
|
||||
ApplicationName = "Maintenance",
|
||||
Name = "SP Expected",
|
||||
Status = 2
|
||||
});
|
||||
result.SendPorts.Add(new SendPortState
|
||||
{
|
||||
ApplicationName = "Orders",
|
||||
Name = "SP Orders",
|
||||
Status = 1
|
||||
});
|
||||
result.SendPorts.Add(new SendPortState
|
||||
{
|
||||
ApplicationName = "Orders",
|
||||
Name = "SP Active",
|
||||
Status = 3
|
||||
});
|
||||
|
||||
var line = FindServiceLine(result, "Send Ports", options);
|
||||
Assert(line.StartsWith("2 \"BizTalk Send Ports\"", StringComparison.Ordinal), "unexpected inactive send port must be CRIT");
|
||||
Assert(line.Contains("biztalk_send_ports_started=1"), "started send port metric missing");
|
||||
Assert(line.Contains("biztalk_send_ports_unexpected_inactive=1"), "unexpected inactive send metric missing");
|
||||
Assert(line.Contains("biztalk_send_ports_expected_inactive=1"), "expected inactive send metric missing");
|
||||
Assert(line.Contains(@"Orders\SP Orders(bound)"), "affected send port missing");
|
||||
Assert(line.IndexOf("SP Expected", StringComparison.Ordinal) < 0, "expected inactive send port should not clutter affected list");
|
||||
|
||||
options.ExpectedInactiveSendPorts = new[] { "Maintenance\\SP Expected", "SP Orders" };
|
||||
var allExpected = FindServiceLine(result, "Send Ports", options);
|
||||
Assert(allExpected.StartsWith("0 \"BizTalk Send Ports\"", StringComparison.Ordinal), "all expected inactive send ports should be OK");
|
||||
Assert(allExpected.Contains("biztalk_send_ports_expected_inactive=2"), "all expected send count missing");
|
||||
}
|
||||
|
||||
private static void UnknownReceiveLocationStateIsNotGreen()
|
||||
{
|
||||
var result = new ProbeResult();
|
||||
result.Platform.ReceiveLocationsDataAvailable = true;
|
||||
result.ReceiveLocations.Add(new ReceiveLocationState
|
||||
{
|
||||
ApplicationName = "Orders",
|
||||
Name = "RL Missing State",
|
||||
IsDisabled = null
|
||||
});
|
||||
|
||||
var line = FindServiceLine(result, "Receive Locations");
|
||||
Assert(line.StartsWith("3 \"BizTalk Receive Locations\"", StringComparison.Ordinal), "unknown receive state must be UNKNOWN");
|
||||
Assert(line.Contains("biztalk_receive_locations_unknown=1"), "unknown receive metric missing");
|
||||
Assert(line.Contains(@"Orders\RL Missing State"), "unknown receive location must be visible");
|
||||
}
|
||||
|
||||
private static void ArtifactSummaryIsBounded()
|
||||
{
|
||||
var options = new MonitoringOptions
|
||||
{
|
||||
MaxSummaryItems = 2,
|
||||
MaxDetailCharacters = 256
|
||||
};
|
||||
var result = new ProbeResult();
|
||||
result.Platform.ReceiveLocationsDataAvailable = true;
|
||||
for (var i = 1; i <= 6; i++)
|
||||
{
|
||||
result.ReceiveLocations.Add(new ReceiveLocationState
|
||||
{
|
||||
ApplicationName = "Application",
|
||||
Name = "Disabled-" + i,
|
||||
IsDisabled = true
|
||||
});
|
||||
}
|
||||
|
||||
var line = FindServiceLine(result, "Receive Locations", options);
|
||||
Assert(line.Contains("(+4 more)"), "omitted item count missing");
|
||||
Assert(line.Length < 700, "local check line should remain compact");
|
||||
|
||||
var longResult = new ProbeResult();
|
||||
longResult.Platform.ReceiveLocationsDataAvailable = true;
|
||||
longResult.ReceiveLocations.Add(new ReceiveLocationState
|
||||
{
|
||||
ApplicationName = new string('A', 400),
|
||||
Name = new string('R', 400),
|
||||
IsDisabled = true
|
||||
});
|
||||
var truncated = FindServiceLine(longResult, "Receive Locations", options);
|
||||
Assert(truncated.Contains("[truncated]"), "detail character limit should be visible");
|
||||
Assert(truncated.Length < 700, "truncated local check line should remain bounded");
|
||||
}
|
||||
|
||||
private static void SnapshotRoundTripPreservesLines()
|
||||
{
|
||||
WithTemporarySnapshot((path, store) =>
|
||||
@@ -222,7 +392,7 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
var lines = new CheckmkLocalFormatter(new MonitoringOptions())
|
||||
.FormatSnapshotFailure("Snapshot file does not exist.")
|
||||
.ToArray();
|
||||
AssertEqual(6, lines.Length, "snapshot failure stable service count");
|
||||
AssertEqual(8, lines.Length, "snapshot failure stable service count");
|
||||
Assert(lines.All(x => x.StartsWith("3 \"BizTalk ", StringComparison.Ordinal)), "snapshot failure must be UNKNOWN");
|
||||
Assert(lines.All(x => x.Contains("Scheduled Task")), "snapshot failure must contain provider action");
|
||||
}
|
||||
@@ -258,6 +428,18 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string FindServiceLine(
|
||||
ProbeResult result,
|
||||
string serviceSuffix,
|
||||
MonitoringOptions options = null)
|
||||
{
|
||||
var effectiveOptions = options ?? new MonitoringOptions();
|
||||
var token = "\"" + effectiveOptions.ServiceName(serviceSuffix) + "\"";
|
||||
return new CheckmkLocalFormatter(effectiveOptions)
|
||||
.Format(result)
|
||||
.Single(x => x.Contains(token));
|
||||
}
|
||||
|
||||
private static void Run(string name, Action test)
|
||||
{
|
||||
ExecutedTests++;
|
||||
|
||||
Reference in New Issue
Block a user