0

Query Workers Observability

by
Published today

Query Workers Logs telemetry (events, invocations or aggregate calculations) for the account or one Worker over the last 7 days. Needs Workers Observability permission on the token.

Script cloudflare Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 3 hours ago
1
//native
2

3
export type DynSelect_worker_name = string
4

5
// Dropdown of the account's Worker scripts.
6
export async function worker_name(auth: RT.Cloudflare) {
7
  const response = await fetch(
8
    `https://api.cloudflare.com/client/v4/accounts/${auth.account_id}/workers/scripts`,
9
    {
10
      headers: {
11
        Authorization: `Bearer ${auth.token}`,
12
        Accept: "application/json",
13
      },
14
    }
15
  )
16
  if (!response.ok) {
17
    throw new Error(`${response.status} ${await response.text()}`)
18
  }
19
  const { result } = (await response.json()) as { result: { id: string }[] }
20
  return result.map((s) => ({ value: s.id, label: s.id }))
21
}
22

23
/**
24
 * Query Workers Observability
25
 * Query Workers Logs telemetry (events, invocations or aggregate calculations) for the account or one Worker over the last 7 days. Needs Workers Observability permission on the token.
26
 */
27
export async function main(
28
  auth: RT.Cloudflare,
29
  view: "events" | "invocations" | "calculations",
30
  worker_name: DynSelect_worker_name | undefined,
31
  from: string | undefined,
32
  to: string | undefined,
33
  search: string | undefined,
34
  filters:
35
    | {
36
        key: string
37
        operation: string
38
        type: "string" | "number" | "boolean"
39
        value?: string | number | boolean
40
      }[]
41
    | undefined,
42
  calculations:
43
    | {
44
        operator: string
45
        key?: string
46
        keyType?: "string" | "number" | "boolean"
47
        alias?: string
48
      }[]
49
    | undefined,
50
  group_by: string[] | undefined,
51
  limit: number | undefined
52
) {
53
  const toMs = to ? Date.parse(to) : Date.now()
54
  const fromMs = from ? Date.parse(from) : toMs - 60 * 60 * 1000
55

56
  const allFilters: { [key: string]: any }[] = (filters ?? []).map((f) => ({
57
    kind: "filter",
58
    ...f,
59
  }))
60
  if (worker_name) {
61
    allFilters.unshift({
62
      kind: "filter",
63
      key: "$metadata.service",
64
      operation: "eq",
65
      type: "string",
66
      value: worker_name,
67
    })
68
  }
69

70
  const response = await fetch(
71
    `https://api.cloudflare.com/client/v4/accounts/${auth.account_id}/workers/observability/telemetry/query`,
72
    {
73
      method: "POST",
74
      headers: {
75
        Authorization: `Bearer ${auth.token}`,
76
        "Content-Type": "application/json",
77
        Accept: "application/json",
78
      },
79
      body: JSON.stringify({
80
        queryId: `windmill-${view}`,
81
        view,
82
        // dry keeps the query out of the account's saved-query history
83
        dry: true,
84
        timeframe: { from: fromMs, to: toMs },
85
        limit: limit ?? 50,
86
        parameters: {
87
          datasets: ["cloudflare-workers"],
88
          filterCombination: "and",
89
          filters: allFilters,
90
          needle: search ? { value: search } : undefined,
91
          calculations:
92
            calculations ??
93
            (view === "calculations" ? [{ operator: "count" }] : undefined),
94
          groupBys: group_by?.map((value) => ({ value, type: "string" })),
95
          limit: limit ?? 50,
96
        },
97
      }),
98
    }
99
  )
100

101
  if (!response.ok) {
102
    throw new Error(`${response.status} ${await response.text()}`)
103
  }
104

105
  return await response.json()
106
}
107