Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/datadog

src/monitors.ts

193 lines · 7.7 KB · TypeScript
import { asStringArray, clean, datadogRequest, mutationPreview, positiveInt } from './core.ts'
import type { DatadogMonitorInput } from './types.ts'

function monitorId(params: DatadogMonitorInput): string {
	const id = clean(params.monitorId ?? params.id)
	if (!id) throw new Error('monitorId is required.')
	return id
}

function summarizeMonitor(monitor: any) {
	return {
		id: monitor?.id ?? null,
		name: monitor?.name ?? null,
		type: monitor?.type ?? null,
		overallState: monitor?.overall_state ?? monitor?.overallState ?? null,
		query: monitor?.query ?? null,
		tags: Array.isArray(monitor?.tags) ? monitor.tags : [],
		priority: monitor?.priority ?? null,
		created: monitor?.created ?? null,
		modified: monitor?.modified ?? null,
		creator: monitor?.creator?.handle ?? monitor?.creator?.email ?? null,
	}
}

function monitorBody(params: DatadogMonitorInput): Record<string, unknown> {
	if (params.body && typeof params.body === 'object') return params.body
	const body: Record<string, unknown> = {}
	if (clean(params.type)) body.type = clean(params.type)
	if (clean(params.query)) body.query = clean(params.query)
	if (clean(params.name)) body.name = clean(params.name)
	if (clean(params.message)) body.message = clean(params.message)
	const tags = asStringArray(params.tags)
	if (tags.length) body.tags = tags
	if (params.options && typeof params.options === 'object') body.options = params.options
	if (params.priority != null) body.priority = params.priority
	if (Array.isArray(params.restrictedRoles)) body.restricted_roles = params.restrictedRoles
	if (clean(params.draftStatus)) body.draft_status = clean(params.draftStatus)
	return body
}

/** List monitors. GET /api/v1/monitor */
export async function listMonitors(params: DatadogMonitorInput = {}) {
	const query: Record<string, unknown> = {}
	if (clean(params.name)) query.name = clean(params.name)
	const tags = asStringArray(params.tags)
	if (tags.length) query.tags = tags.join(',')
	const monitorTags = asStringArray(params.monitorTags)
	if (monitorTags.length) query.monitor_tags = monitorTags.join(',')
	const groupStates = asStringArray(params.groupStates)
	if (groupStates.length) query.group_states = groupStates.join(',')
	if (params.withDowntimes === true) query.with_downtimes = true
	if (params.page != null) query.page = positiveInt(params.page, 0, 10_000)
	if (params.pageSize != null || params.perPage != null) {
		query.page_size = positiveInt(params.pageSize ?? params.perPage, 30, 1000)
	}
	const body = await datadogRequest('/api/v1/monitor', { ...params, query })
	const monitors = Array.isArray(body) ? body : Array.isArray(body?.monitors) ? body.monitors : []
	return {
		count: monitors.length,
		monitors: monitors.map(summarizeMonitor),
	}
}

/** Get one monitor. GET /api/v1/monitor/{monitor_id} */
export async function getMonitor(params: DatadogMonitorInput = {}) {
	const id = monitorId(params)
	const monitor = await datadogRequest('/api/v1/monitor/' + encodeURIComponent(id), params)
	return { monitor: summarizeMonitor(monitor), raw: monitor }
}

/** Search monitors. GET /api/v1/monitor/search */
export async function searchMonitors(params: DatadogMonitorInput = {}) {
	const query: Record<string, unknown> = {}
	if (clean(params.query)) query.query = clean(params.query)
	if (params.page != null) query.page = positiveInt(params.page, 0, 10_000)
	if (params.perPage != null || params.pageSize != null) {
		query.per_page = positiveInt(params.perPage ?? params.pageSize, 30, 200)
	}
	const body = await datadogRequest('/api/v1/monitor/search', { ...params, query })
	const monitors = Array.isArray(body?.monitors) ? body.monitors : []
	return {
		count: monitors.length,
		total: body?.metadata?.total_count ?? body?.metadata?.total ?? monitors.length,
		monitors: monitors.map((item: any) => summarizeMonitor(item)),
		counts: body?.counts ?? null,
	}
}

/** Create a monitor. Requires confirm. Pass dryRun: true to preview. */
export async function createMonitor(params: DatadogMonitorInput = {}) {
	const body = monitorBody(params)
	if (!clean(body.type) || !clean(body.query)) {
		throw new Error('Creating a monitor requires type and query (or a full body).')
	}
	const preview = mutationPreview(params, {
		action: 'create monitor ' + (clean(body.name) || clean(body.query)),
		method: 'POST',
		path: '/api/v1/monitor',
		body,
	})
	if (preview) return preview
	const created = await datadogRequest('/api/v1/monitor', { ...params, method: 'POST', body })
	return { ok: true, action: 'create', monitor: summarizeMonitor(created), raw: created }
}

/** Update a monitor. Requires confirm. Pass dryRun: true to preview. */
export async function updateMonitor(params: DatadogMonitorInput = {}) {
	const id = monitorId(params)
	const body = monitorBody(params)
	const preview = mutationPreview(params, {
		action: 'update monitor ' + id,
		method: 'PUT',
		path: '/api/v1/monitor/' + encodeURIComponent(id),
		body,
	})
	if (preview) return preview
	const updated = await datadogRequest('/api/v1/monitor/' + encodeURIComponent(id), {
		...params,
		method: 'PUT',
		body,
	})
	return { ok: true, action: 'update', monitor: summarizeMonitor(updated), raw: updated }
}

/** Delete a monitor. Requires confirm. Pass dryRun: true to preview. */
export async function deleteMonitor(params: DatadogMonitorInput = {}) {
	const id = monitorId(params)
	const preview = mutationPreview(params, {
		action: 'delete monitor ' + id,
		method: 'DELETE',
		path: '/api/v1/monitor/' + encodeURIComponent(id),
	})
	if (preview) return preview
	const deleted = await datadogRequest('/api/v1/monitor/' + encodeURIComponent(id), {
		...params,
		method: 'DELETE',
	})
	return { ok: true, action: 'delete', monitorId: id, raw: deleted }
}

/** Mute a monitor. Requires confirm. Pass dryRun: true to preview. */
export async function muteMonitor(params: DatadogMonitorInput = {}) {
	const id = monitorId(params)
	const body: Record<string, unknown> = {}
	if (clean(params.scope)) body.scope = clean(params.scope)
	if (params.end != null) body.end = params.end
	const preview = mutationPreview(params, {
		action: 'mute monitor ' + id,
		method: 'POST',
		path: '/api/v1/monitor/' + encodeURIComponent(id) + '/mute',
		body: Object.keys(body).length ? body : undefined,
	})
	if (preview) return preview
	const muted = await datadogRequest('/api/v1/monitor/' + encodeURIComponent(id) + '/mute', {
		...params,
		method: 'POST',
		body: Object.keys(body).length ? body : undefined,
	})
	return { ok: true, action: 'mute', monitor: summarizeMonitor(muted), raw: muted }
}

/** Unmute a monitor. Requires confirm. Pass dryRun: true to preview. */
export async function unmuteMonitor(params: DatadogMonitorInput = {}) {
	const id = monitorId(params)
	const body: Record<string, unknown> = {}
	if (clean(params.scope)) body.scope = clean(params.scope)
	if (params.allScopes === true) body.all_scopes = true
	const preview = mutationPreview(params, {
		action: 'unmute monitor ' + id,
		method: 'POST',
		path: '/api/v1/monitor/' + encodeURIComponent(id) + '/unmute',
		body: Object.keys(body).length ? body : undefined,
	})
	if (preview) return preview
	const unmuted = await datadogRequest('/api/v1/monitor/' + encodeURIComponent(id) + '/unmute', {
		...params,
		method: 'POST',
		body: Object.keys(body).length ? body : undefined,
	})
	return { ok: true, action: 'unmute', monitor: summarizeMonitor(unmuted), raw: unmuted }
}

/**
 * List, search, or get Datadog monitors. Mutations live on named exports.
 * @example
 * import { listMonitors } from 'kody:@kody/datadog/monitors'
 * const result = await listMonitors({ pageSize: 20 })
 */
export default async function monitors(params: DatadogMonitorInput = {}) {
	if (params.monitorId || params.id) return await getMonitor(params)
	if (clean(params.query)) return await searchMonitors(params)
	return await listMonitors(params)
}