| 76 | } |
| 77 | |
| 78 | function buildEntries( |
| 79 | rows: unknown[], |
| 80 | config: DatadogDestinationConfig, |
| 81 | metadata: DeliveryMetadata |
| 82 | ): DatadogLogEntry[] { |
| 83 | const ddtags = [ |
| 84 | `sim_drain_id:${metadata.drainId}`, |
| 85 | `sim_run_id:${metadata.runId}`, |
| 86 | `sim_source:${metadata.source}`, |
| 87 | ...(config.tags ? [config.tags] : []), |
| 88 | ].join(',') |
| 89 | const service = config.service ?? 'sim' |
| 90 | return rows.map((row) => { |
| 91 | const attrs = typeof row === 'object' && row !== null ? (row as Record<string, unknown>) : {} |
| 92 | let message: string |
| 93 | if (typeof row === 'string') { |
| 94 | message = row |
| 95 | } else if (typeof attrs.message === 'string') { |
| 96 | message = attrs.message |
| 97 | } else { |
| 98 | message = JSON.stringify(row) |
| 99 | } |
| 100 | /** |
| 101 | * Spread user attributes first, then force all four reserved fields the |
| 102 | * drain owns: `ddsource`, `service`, `ddtags`, and `message`. Per |
| 103 | * https://docs.datadoghq.com/logs/log_configuration/pipelines/#service-and-source, |
| 104 | * Datadog uses `service` + `ddsource` to pick the processing pipeline, so |
| 105 | * letting a row field clobber them would silently re-route a drain. |
| 106 | */ |
| 107 | return { |
| 108 | ...attrs, |
| 109 | ddsource: 'sim', |
| 110 | service, |
| 111 | ddtags, |
| 112 | message, |
| 113 | } |
| 114 | }) |
| 115 | } |
| 116 | |
| 117 | function isRetryableStatus(status: number): boolean { |
| 118 | return status === 408 || status === 429 || status >= 500 |