Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | 28x 28x 28x 28x 28x 28x 34x 34x 19x 19x 19x 14x 5x 5x 4x 1x 5x | import { Logger } from '@bayudwiyansatria/core'
import { Binding } from '@/core/bindings/Binding'
import { events } from '@/constants/Events'
import { MissingBindingError } from '@/exceptions/MissingBindingError'
import { lazySettings } from '@/utils/lazySettings'
import { AnalyticsSettings } from '@/types/AnalyticsSettings'
import type { CloudflareEnv } from '@/types/CloudflareEnv'
/**
* Accessor for the Analytics Engine dataset binding
* (`analytics_engine_datasets` in `wrangler.json`).
*
* The dataset carries telemetry — measurements to aggregate — and never log
* lines: Analytics Engine samples at volume, so an individual line written here
* may simply not be there when it is needed. Logging belongs to `Logger` in
* `@bayudwiyansatria/core`, which writes to the runtime's log stream instead.
*
* @example
* ```ts
* const dataset = new AnalyticsBinding() // binding name from the configuration layer
*
* dataset.writeSafe(ctx.env, {
* indexes: ['/api/v1/articles'], // sampling key
* blobs: ['POST', '201'], // dimensions to filter by
* doubles: [42, 1] // duration and a unit count
* })
* ```
*
* @class
*
* @author Bayu Dwiyan Satria
* @version 1.0.0
* @since 1.0.0
*/
export class AnalyticsBinding<E extends CloudflareEnv = CloudflareEnv> extends Binding<AnalyticsEngineDataset, E> {
/**
* Constructs an AnalyticsBinding instance.
*
* @param settings Resolved settings. Defaults to `resolve('analytics')`, so callers
* normally construct this with no arguments at all.
*/
constructor(settings?: AnalyticsSettings) {
const settle = lazySettings<AnalyticsSettings>('analytics', settings)
super(() => settle().binding)
}
/**
* Writes a data point to the dataset.
*
* @param env The Worker environment.
* @param event The data point — blobs, doubles, and indexes.
* @throws {@link MissingBindingError} When the Analytics Engine binding is absent.
*/
public write(env: E, event: AnalyticsEngineDataPoint): void {
this.resolve(env).writeDataPoint(event)
}
/**
* Writes a data point, swallowing any failure.
*
* Telemetry is never worth failing a request over, so a missing binding or a
* rejected write is logged and reported through the return value instead of
* propagating.
*
* @remarks
* The two failures are not the same event, and conflating them is what made
* the earlier version of this method unreadable in production. A Worker with
* no `TELEMETRY` dataset bound is *configured that way* — it is the degraded
* path this accessor documents — so an error line per request would be a
* permanent, sampled, billed restatement of a deployment decision. A write
* that was accepted and then rejected is a real fault, and rare enough to be
* worth a line.
*
* Both go through `Logger` rather than `console.error` directly, so the line
* is one indexed JSON object like every other and `analytics.error` is a
* filter rather than a substring search.
*
* @param env The Worker environment.
* @param event The data point — blobs, doubles, and indexes.
* @returns `true` when the write was accepted, `false` when it failed.
*/
public writeSafe(env: E, event: AnalyticsEngineDataPoint): boolean {
try {
this.write(env, event)
return true
} catch (e) {
const log = Logger.fromEnv(env, { component: 'AnalyticsBinding' })
if (e instanceof MissingBindingError) {
log.debug(events.ANALYTICS_ERROR, { reason: 'binding_absent', binding: this.name })
} else {
log.warn(events.ANALYTICS_ERROR, { reason: 'write_rejected', error: e })
}
return false
}
}
}
|