cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Dashboard tile showing Hosts currently in an Unmonitored state

Ronald
Dynatrace Promoter
Dynatrace Promoter

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!

6 REPLIES 6

AntonPineiro
DynaMight Guru
DynaMight Guru

Hi,

I would create a markdown tile with a link to Deployment status with your filters there.

Best regards

❤️ Emacs ❤️ Vim ❤️ Bash ❤️ Perl

Ronald
Dynatrace Promoter
Dynatrace Promoter

Yeah, that's my "for now" work around.  I do appreciate the response.

tomaxp
Advisor

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.

Ronald
Dynatrace Promoter
Dynatrace Promoter

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.   

tomaxp
Advisor

@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.



Ronald
Dynatrace Promoter
Dynatrace Promoter

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!

Featured Posts