Vite/React + shadcn/ui frontend with Superhuman-style keyboard nav (j/k/o/v/e/s/u, feed switching, localStorage caching for instant loads) backed by an Express API that polls the HN Firebase API into Postgres and serves cached feeds/comments. Instrumented with OpenTelemetry (traces/metrics/logs via OTLP/HTTP).
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
// OpenTelemetry bootstrap: sends traces, metrics and logs to the LGTM
|
||||
// stack's OTLP/HTTP collector at http://localhost:4318. Must be required
|
||||
// before any other module so auto-instrumentation can patch http/express/pg.
|
||||
const { NodeSDK } = require('@opentelemetry/sdk-node')
|
||||
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')
|
||||
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http')
|
||||
const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-http')
|
||||
const { OTLPLogExporter } = require('@opentelemetry/exporter-logs-otlp-http')
|
||||
const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics')
|
||||
const { BatchLogRecordProcessor } = require('@opentelemetry/sdk-logs')
|
||||
const { resourceFromAttributes } = require('@opentelemetry/resources')
|
||||
const { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } = require('@opentelemetry/semantic-conventions')
|
||||
const { logs } = require('@opentelemetry/api-logs')
|
||||
|
||||
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318'
|
||||
|
||||
const resource = resourceFromAttributes({
|
||||
[ATTR_SERVICE_NAME]: 'hn-reader-api',
|
||||
[ATTR_SERVICE_VERSION]: '1.0.0',
|
||||
})
|
||||
|
||||
const sdk = new NodeSDK({
|
||||
resource,
|
||||
traceExporter: new OTLPTraceExporter({ url: `${endpoint}/v1/traces` }),
|
||||
metricReader: new PeriodicExportingMetricReader({
|
||||
exporter: new OTLPMetricExporter({ url: `${endpoint}/v1/metrics` }),
|
||||
exportIntervalMillis: 15000,
|
||||
}),
|
||||
logRecordProcessors: [
|
||||
new BatchLogRecordProcessor(new OTLPLogExporter({ url: `${endpoint}/v1/logs` })),
|
||||
],
|
||||
instrumentations: [
|
||||
getNodeAutoInstrumentations({
|
||||
'@opentelemetry/instrumentation-fs': { enabled: false },
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
sdk.start()
|
||||
|
||||
process.on('SIGTERM', () => sdk.shutdown().finally(() => process.exit(0)))
|
||||
|
||||
const otelLogger = logs.getLogger('hn-reader-api')
|
||||
|
||||
// Small structured logger: prints to stdout (captured by journald) and
|
||||
// emits an OTLP log record so logs show up alongside traces in Grafana.
|
||||
function log(severity, message, attributes = {}) {
|
||||
const line = `[${severity}] ${message} ${Object.keys(attributes).length ? JSON.stringify(attributes) : ''}`
|
||||
if (severity === 'ERROR') console.error(line)
|
||||
else console.log(line)
|
||||
|
||||
otelLogger.emit({
|
||||
severityText: severity,
|
||||
body: message,
|
||||
attributes,
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { log }
|
||||
Reference in New Issue
Block a user