@ogcio/o11y-sdk-node
Version:
Opentelemetry standard instrumentation SDK for NodeJS based project
82 lines (81 loc) • 3.15 kB
JavaScript
import { context, defaultTextMapGetter, propagation, } from "@opentelemetry/api";
import { encodeGeohash } from "./geohash.js";
export const geoBaggageKeys = ["geo.country", "geo.city", "geo.hash"];
/**
* CloudFront viewer header names carrying geo information.
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/adding-cloudfront-headers.html
*/
export const CF_GEO_HEADERS = {
COUNTRY: "cloudfront-viewer-country",
CITY: "cloudfront-viewer-city",
LATITUDE: "cloudfront-viewer-latitude",
LONGITUDE: "cloudfront-viewer-longitude",
};
/** Reads a single header value, collapsing multi-valued headers to their first entry. */
export function getHeaderValue(carrier, key, getter = defaultTextMapGetter) {
const value = getter.get(carrier, key);
return Array.isArray(value) ? value[0] : value;
}
function fromBaggage(baggage) {
if (!baggage)
return {};
const attrs = {};
for (const key of geoBaggageKeys) {
const value = baggage.getEntry(key)?.value;
if (value)
attrs[key] = value;
}
return attrs;
}
/**
* Returns geo attributes from the given OTel context's baggage.
* Use this in span and log processors where the context is passed explicitly.
*/
export function getGeoAttributesFromContext(ctx) {
return fromBaggage(propagation.getBaggage(ctx));
}
/**
* Returns geo attributes for the current request context.
* Reads from OTel Baggage on the active context, set by GeoBaggagePropagator.
* Use this to manually enrich custom spans, logs, or metrics when geo-enrichment is enabled.
*/
export function getGeoAttributes() {
return fromBaggage(propagation.getBaggage(context.active()));
}
/**
* Builds geo attributes from any combination of geo inputs.
* A geohash is computed automatically when both `lat` and `lon` are provided.
* Use this to create geo attributes to attach to signals when auto-enrichment is not enabled.
*/
export function createGeoAttributesFrom(input) {
const attrs = {};
if (input.country) {
attrs["geo.country"] = input.country;
}
if (input.city) {
attrs["geo.city"] = input.city;
}
const hash = encodeGeohash(input.lat, input.lon, input.precision);
if (hash) {
attrs["geo.hash"] = hash;
}
return attrs;
}
/**
* Builds geo attributes directly from provider headers.
* Use this to enrich a single span, log, or metric when auto-enrichment is not enabled.
*/
export function createGeoAttributesFromHeaders(carrier, options = {}) {
const { getter = defaultTextMapGetter, precision, headerMap = CF_GEO_HEADERS, } = options;
const country = getHeaderValue(carrier, headerMap.COUNTRY, getter);
const city = getHeaderValue(carrier, headerMap.CITY, getter);
const latStr = getHeaderValue(carrier, headerMap.LATITUDE, getter);
const lonStr = getHeaderValue(carrier, headerMap.LONGITUDE, getter);
return createGeoAttributesFrom({
country,
city,
lat: latStr !== undefined ? parseFloat(latStr) : undefined,
lon: lonStr !== undefined ? parseFloat(lonStr) : undefined,
precision,
});
}