Skip to content

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

Package listing

@kody/datadog

src/logs.ts

63 lines · 2.0 KB · TypeScript
import { asStringArray, clean, datadogRequest, positiveInt } from './core.ts'
import type { DatadogLogsInput } from './types.ts'

function summarizeLog(item: any) {
	const attributes = item?.attributes ?? item ?? {}
	const extra = attributes.attributes ?? {}
	return {
		id: item?.id ?? null,
		timestamp: attributes.timestamp ?? extra.timestamp ?? null,
		message: attributes.message ?? extra.message ?? null,
		status: attributes.status ?? extra.status ?? null,
		service: attributes.service ?? extra.service ?? null,
		host: attributes.host ?? extra.host ?? null,
		tags: Array.isArray(attributes.tags) ? attributes.tags : [],
	}
}

/**
 * Search logs. POST /api/v2/logs/events/search
 *
 * Pass a Logs Explorer query, plus `from` / `to` (ISO-8601 or `now-15m`).
 * Read-only — never writes logs.
 *
 * @example
 * import { searchLogs } from 'kody:@kody/datadog/logs'
 * const result = await searchLogs({ query: 'status:error', from: 'now-15m', to: 'now' })
 */
export async function searchLogs(params: DatadogLogsInput = {}) {
	const query = clean(params.query) || '*'
	const from = clean(params.from) || 'now-15m'
	const to = clean(params.to) || 'now'
	const indexes = asStringArray(params.indexes)
	const filter: Record<string, unknown> = { query, from, to }
	if (indexes.length) filter.indexes = indexes
	if (clean(params.storageTier)) filter.storage_tier = clean(params.storageTier)

	const body: Record<string, unknown> = {
		filter,
		sort: clean(params.sort) || '-timestamp',
		page: {
			limit: positiveInt(params.limit, 10, 1000),
		},
	}
	if (clean(params.cursor)) (body.page as Record<string, unknown>).cursor = clean(params.cursor)

	const response = await datadogRequest('/api/v2/logs/events/search', {
		...params,
		method: 'POST',
		body,
		label: 'Datadog logs search',
	})
	const events = Array.isArray(response?.data) ? response.data : []
	return {
		count: events.length,
		query,
		from,
		to,
		logs: events.map(summarizeLog),
		nextCursor: response?.meta?.page?.after ?? null,
	}
}

export default searchLogs