16 Sep 2025 03:16 PM
In Dynatrace Managed, I'm trying to use the Metric Host Availability State to show currently unmonitored hosts
builtin:host.availability.state:filter(eq("availability.state","unmonitored_agent_stopped")):splitBy("host.name","availability.state"):sort(value(auto,descending))
Issue is this shows every host that has ever entered the filtered state during the timeframe. Is there a way to combine these results with additional metrics to show what is currently unmonitored? I can make it happen via API and excel but not via the data explorer. Client wants this info as a dashboard tile.
Thanks!
16 Sep 2025 03:40 PM
Hi,
I would create a markdown tile with a link to Deployment status with your filters there.
Best regards
17 Sep 2025 06:54 PM
Yeah, that's my "for now" work around. I do appreciate the response.
18 Sep 2025 08:13 AM
Try this:
builtin:host.availability.state
:filter(eq("availability.state","unmonitored_agent_stopped"))
:splitBy("host.name")
Because builtin:host.availability.state returns all occurrences within the selected timeframe, long time ranges will include past unmonitored states. Using a short timeframe with Last value filtering shows only hosts that are currently unmonitored — filtering out those that were unmonitored earlier but have since recovered.
18 Sep 2025 03:11 PM
Unfortunately, this only shows any host that polled in that timeframe as unmonitored. Any host that entered an Unmonitored state hours or days ago and are still that way do not appear.
18 Sep 2025 03:50 PM
@Ronald You have right.
So we can achive this by API.
#!/usr/bin/env python3
import requests
import datetime as dt
import time
# === KONFIGURACJA ===
DT_BASE_URL = "https://dynatrace.example.com/e/ENV-ID" # Your Managed/SaaS base URL
DT_API_TOKEN = "dt0c01.xxxxx.yyyyy" # Token with correct permissions (oneAgents.read and DataExport)
DAYS_BACK = 150 # Default timeframe (max 214 days)
INCLUDE_DETAILS = "false" # "true" or "false"
MANAGEMENT_ZONE = None # e.g., "PROD" or None
MANAGEMENT_ZONE_ID = None # e.g., 123456789012345 or None
TAGS = [] # e.g., ["env:prod","team:backend"]
NETWORK_ZONE_ID = None # e.g., "NETWORK_ZONE-123456789"
# ====================
MAX_DAYS = 214
def iso_utc(ms: int) -> str:
return dt.datetime.utcfromtimestamp(ms/1000.0).strftime("%Y-%m-%dT%H:%M:%SZ")
def build_time_params(days_back: int):
days = min(max(int(days_back), 1), MAX_DAYS)
end_ts = int(time.time() * 1000)
start_ts = end_ts - days * 24 * 60 * 60 * 1000
return {"startTimestamp": start_ts, "endTimestamp": end_ts}
def fetch_unmonitored():
url = f"{DT_BASE_URL.rstrip('/')}/api/v1/oneagents"
headers = {"Authorization": f"Api-Token {DT_API_TOKEN}"}
params = {
"availabilityState": "UNMONITORED",
"includeDetails": INCLUDE_DETAILS,
**build_time_params(DAYS_BACK),
}
if MANAGEMENT_ZONE_ID:
params["managementZoneId"] = MANAGEMENT_ZONE_ID
elif MANAGEMENT_ZONE:
params["managementZone"] = MANAGEMENT_ZONE
if TAGS:
params["tag"] = TAGS
if NETWORK_ZONE_ID:
params["networkZoneId"] = NETWORK_ZONE_ID
results = []
while True:
resp = requests.get(url, headers=headers, params=params, timeout=30)
resp.raise_for_status()
data = resp.json()
for ha in data.get("hosts", []):
host = ha.get("hostInfo", {}) or {}
name = host.get("displayName") or host.get("discoveredName") or host.get("entityId")
availability = ha.get("availabilityState")
detailed = ha.get("detailedAvailabilityState")
last_seen = host.get("lastSeenTimestamp")
if availability == "UNMONITORED":
results.append({
"name": name,
"since": last_seen,
"detail": detailed or "-",
})
next_key = data.get("nextPageKey")
if not next_key:
break
params["nextPageKey"] = next_key
return results
if __name__ == "__main__":
try:
rows = fetch_unmonitored()
except requests.HTTPError as e:
body = e.response.text if e.response is not None else ""
print(f"HTTP error: {e}\nBody: {body}")
raise SystemExit(1)
if not rows:
print("No UNMONITORED hosts found in the given timeframe.")
raise SystemExit(0)
# longest unmonitored at the top
rows.sort(key=lambda r: (r["since"] or 0))
print(f"{'HOST':50} {'SINCE (UTC)':20} {'DETAIL'}")
print("-"*50 + " " + "-"*20 + " " + "-"*20)
for r in rows:
since = iso_utc(r["since"]) if r["since"] else "-"
print(f"{r['name'][:50]:50} {since:20} {r['detail']}")
This script:
Queries /api/v1/oneagents for hosts with availabilityState=UNMONITORED over the last DAYS_BACK days (max 214).
Supports optional filters: management zone (name/ID), tags, network zone.
Paginates with nextPageKey to fetch all results.
Collects each host’s name, last seen timestamp (approx. when it became unmonitored), and detailed availability state.
Sorts by oldest lastSeenTimestamp first and prints a table: HOST | SINCE (UTC) | DETAIL.
Optionally, you can extend it to push results via Metric Ingest (e.g. custom.unmonitored.hosts.total, custom.unmonitored.host.present) so you can visualize them directly in Dynatrace dashboards.
18 Sep 2025 04:35 PM - edited 18 Sep 2025 04:37 PM
As one who knows nothing about programing this is both jaw dropping and amazing. The best I have been able to do is present a list to the client as an excel sheet I created using API! I'll look up how to complete the Metric Ingest portion. Then I'll see if it's something that would be manually run or could be scheduled! Thank you so much!