import Transport from 'winston-transport' import fetch from 'node-fetch' import { DataDogTransportOptions } from './types' interface QueryParams { hostname?: string service?: string ddsource: string ddtags?: string } interface Log { dd?: { [key: string]: string } } class DataDogTransport extends Transport { private ddsource = 'nodejs' constructor(private options: DataDogTransportOptions) { super({ level: options.level, format: options.format }) } get name() { return 'datadog' } async log(log: Log, callback: () => void) { setImmediate(() => { this.emit('logged', log) }) const queryParams = this._getQueryParams(log) const url = this._getUrl(queryParams) try { await fetch(url, { method: 'POST', headers: { 'content-type': 'application/json', }, body: JSON.stringify(log), }) } catch (err) { } finally { callback() } } _getQueryParams(log: Log) { const queryParams: QueryParams = { hostname: this.options.hostname, service: this.options.service, ddsource: this.ddsource, ddtags: this._getDDTags(log), } return queryParams } _getUrl(queryParams: QueryParams) { const url = new URL(this.options.apiKey, this.options.intakeUrl) Object.keys(queryParams).forEach((param) => { const value = queryParams[param as keyof QueryParams] if (value == undefined || !value.length) return url.searchParams.append(param, value) }) return url.toString() } _getDDTags(log: Log) { let tags = this.options.ddtags || '' const addTag = (key: string, value: string) => (tags += (tags.length ? ',' : '') + `${key}:${value}`) if (log.dd?.trace_id) addTag('trace_id', log.dd.trace_id) if (log.dd?.span_id) addTag('span_id', log.dd.span_id) if (this.options.storefrontVersion) addTag('version', this.options.storefrontVersion) if (this.options.siteState) addTag('site_state', this.options.siteState) return tags } } export { DataDogTransport }