Koll
This is a very basic logging library mainly for communicating with grafana's faro backend.
It massively cuts back on functionality compared to opentelemetry + faro-web-sdk, and you should definitely just use those.
This is just the bare minimum that was enough for me.
Installation
npm install koll
Usage
To get started you need to set up an exporter, there is one included for communicating with faro, and a couple of utility exporters.
Here's an example:
import { lightBrowserDetect, measurement } from "koll"
import { faroExporter } from "koll/exporters/faro"
import { batchingExporter } from "koll/exporters/batching"
const faro = faroExporter({
destination: 'http://localhost:12345/collect',
meta: () => ({
app: {
name: 'web',
version: '0.0.1',
},
page: {
url: location.href,
},
browser: lightBrowserDetect()
})
});
const batching = batchingExporter(faro, {
});
const myExporter = async (...messages: ExportItem[]) => await batching(...messages);
When you have an exporter set up you're ready to send messages.
There are a few default instrumentations that can be enabled, these are just functions that will call the global exporter with logs and measurements. Let's look at those first:
import { instrumentResourceTiming } from "koll/instrument/resource-timing"
import { instrumentWebVitals } from "koll/instrument/web-vitals"
import { instrumentUnhandledErrors } from "koll/instrument/unhandled-errors"
instrumentResourceTiming(myExporter);
instrumentWebVitals(myExporter);
const stop = instrumentUnhandledErrors(myExporter, {
});
On top of that you can of course create your own traces and messages:
import {tracer} from "koll";
const trace = tracer(myExporter, request.headers['traceparent']);
const result = await trace.run('some-scope-name', async (span) => {
span.name = 'getting some things';
span.attributes.push({
key: 'http.response_status',
value: { intValue: 200 }
});
span.cancel();
const result = await span.run('some-other-scope', (childSpan) => {
return await fetch('/', { headers: { traceparent: childSpan.traceparent() }});
)});
return result;
});
trace.measurement('my-scope', 'http.response_time', 'ms', 200);
trace.log('my-scope', 20, 'error log message');
trace.exception('my-scope', new Error('error message'));
trace.span('my-scope', {
name: 'my span',
startTimeUnixNano: millitime(Date.now() - 10000),
endTimeUnixNano: millitime(Date.now()),
});
Miscellaneous
There are a few little extras that can be useful.
web vitals
The web vitals instrumenter logs a few core web vitals, LCP, CLS, TTFB..
import { instrumentWebVitals } from "koll/instrument/web-vitals"
instrumentWebVitals(myExporter);
reporting navigation resource timing segments
The dom load performance instrumenter can be used for things like instrumenting loads during routing.
import {
instrumentResourceTiming,
reportResourceTimingSegment
} from "koll/instrument/resource-timing"
instrumentResourceTiming(myExporter);
const path = '/';
const start = performance.now();
await doRoutingStuff(path);
const end = performance.now();
reportResourceTimingSegment(`loaded ${path}`, start, end);
unhandled errors
The unhandled errors instrumentation does about what you'd expect.
It listens to error or promise rejection messages and logs them to an exporter.
import { instrumentUnhandledErrors } from "koll/instrument/unhandled-errors"
const stop = instrumentUnhandledErrors(myExporter, {
ignore: err => false
});
stop();
Size
The size of the library will vary a bit based on your usage, there are a couple of files in examples that configure koll differently.
In v0.1.5:
bundle-minimal-test.js is 5.7kb, 2.5kb gzipped.
bundle-large-test.js is 8.9kb, 3.6kb gzipped.