-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 7d0697a
Showing
24 changed files
with
5,449 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"reporter": ["text", "html"], | ||
"all": true, | ||
"statements": "100", | ||
"branches": "100", | ||
"functions": "100", | ||
"lines": "100", | ||
"exclude": ["coverage", "dist", "test", "index.ts", "eslint.config.js"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# EditorConfig is awesome: http://EditorConfig.org | ||
|
||
# top-most EditorConfig file | ||
root = true | ||
|
||
[*] | ||
end_of_line = lf | ||
insert_final_newline = true | ||
charset = utf-8 | ||
indent_style = space | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
|
||
name: Create Release | ||
|
||
jobs: | ||
test: | ||
name: Run tests | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version-file: .nvmrc | ||
cache: npm | ||
|
||
- name: Install dependencies | ||
run: npm ci | ||
|
||
- name: Lint | ||
run: npm run lint | ||
|
||
- name: Check formatting | ||
run: | | ||
npm run format | ||
[[ $(git status --porcelain) ]] && exit 1 | ||
- name: Check types | ||
run: npm run typecheck | ||
|
||
- name: Run tests | ||
run: npm run coverage | ||
|
||
build: | ||
name: Create Release | ||
runs-on: ubuntu-latest | ||
needs: test | ||
if: github.event_name == 'push' && github.ref_name == github.event.repository.default_branch | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Check if package version changed | ||
id: check_version | ||
run: | | ||
version="v$(cat package.json | jq -r '.version')" | ||
if [ $(git tag -l "$version") ]; then | ||
echo "Tag $version already exists." | ||
else | ||
echo "version_tag=$version" >> "$GITHUB_OUTPUT" | ||
fi | ||
- uses: actions/setup-node@v4 | ||
if: steps.check_version.outputs.version_tag | ||
with: | ||
node-version-file: .nvmrc | ||
cache: npm | ||
|
||
# TODO: enable once we are ready | ||
# - name: Create GitHub release | ||
# if: steps.check_version.outputs.version_tag | ||
# run: | | ||
# gh release create ${{ steps.check_version.outputs.version_tag }} --generate-notes | ||
# env: | ||
# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
# - name: Publish to NPM | ||
# if: steps.check_version.outputs.version_tag | ||
# run: | | ||
# npm ci | ||
# npm publish --access public | ||
# env: | ||
# NODE_AUTH_TOKEN: ... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
coverage | ||
dist | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"timeout": 1000, | ||
"reporter": "spec", | ||
"recursive": true, | ||
"ui": "mocha-cakes-2", | ||
"require": ["./test/setup.ts"], | ||
"exit": true, | ||
"extension": ["ts"], | ||
"node-option": ["import=tsx/esm"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
22 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"bracketSpacing": true, | ||
"printWidth": 120, | ||
"arrowParens": "always", | ||
"trailingComma": "es5", | ||
"semi": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# @bonniernews/logger | ||
|
||
## Usage | ||
|
||
```js | ||
import { | ||
fetchGcpProjectId, | ||
getHttpTraceHeader, | ||
getLoggingTraceData, | ||
middleware, | ||
} from "@bonniernews/bn-log-tracer"; | ||
import express from "express"; | ||
import pino from "pino"; | ||
|
||
const logger = pino({ mixin: getLoggingTraceData }); | ||
const app = express(); | ||
|
||
app.use(middleware); | ||
|
||
// Fetches the project ID from the GCP metadata server in the background on startup. | ||
// This is only necessary if you don't set the `GCP_PROJECT` environment variable. | ||
fetchGcpProjectId(); | ||
|
||
app.get("/", async (req, res) => { | ||
logger.info("Hello, world!"); | ||
|
||
const response = await fetch("https://some.service.bn.nr/some/endpoint", { | ||
headers: { ...getHttpTraceHeader() }, | ||
}); | ||
|
||
... | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// @ts-check | ||
|
||
import js from "@eslint/js"; | ||
import ts from "typescript-eslint"; | ||
|
||
export default ts.config(js.configs.recommended, ...ts.configs.recommended, ...ts.configs.strict, { | ||
ignores: ["coverage", "dist"], | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export { fetchGcpProjectId } from "./lib/gcp"; | ||
export { getHttpTraceHeader } from "./lib/http"; | ||
export { getLoggingTraceData } from "./lib/logging"; | ||
export { middleware } from "./lib/middleware"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
let gcpProjectId: string | undefined = undefined; | ||
|
||
export function getGcpProjectId() { | ||
return process.env.GCP_PROJECT || gcpProjectId; | ||
} | ||
|
||
/** | ||
* Fetches the Google Cloud Platform (GCP) project ID from the GCP metadata server. | ||
* | ||
* You only need to call this function if you're not setting the `GCP_PROJECT` environment variable. | ||
*/ | ||
export async function fetchGcpProjectId() { | ||
let gcpMetaData; | ||
/* c8 ignore start */ | ||
try { | ||
gcpMetaData = await import("gcp-metadata"); | ||
} catch { | ||
console.error("Failed to import gcp-metadata module"); | ||
return; | ||
} | ||
/* c8 ignore stop */ | ||
|
||
const isAvailable = await gcpMetaData.isAvailable(); | ||
if (!isAvailable) return; | ||
|
||
gcpProjectId = await gcpMetaData.project("project-id"); | ||
} | ||
|
||
/** | ||
* Resets the GCP project ID, for testing. | ||
*/ | ||
export async function reset() { | ||
gcpProjectId = undefined; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { getStore } from "./middleware"; | ||
|
||
export function getHttpTraceHeader() { | ||
const { traceparent } = getStore(); | ||
if (traceparent) return { traceparent }; | ||
return {}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { getGcpProjectId } from "./gcp"; | ||
import { getStore } from "./middleware"; | ||
import { getTraceFromTraceparent } from "./traceparent"; | ||
|
||
export function getLoggingTraceData() { | ||
const { traceparent, ...rest } = getStore(); | ||
if (!traceparent) return {}; | ||
|
||
const trace = getTraceFromTraceparent(traceparent); | ||
if (!trace) return rest; | ||
|
||
const logData = { traceId: trace.traceId, spanId: trace.parentId, ...rest }; | ||
|
||
const gcpProjectId = getGcpProjectId(); | ||
if (!gcpProjectId) { | ||
console.log("GCP Project ID not found"); | ||
return logData; | ||
} | ||
|
||
return { | ||
...logData, | ||
"logging.googleapis.com/trace": `projects/${gcpProjectId}/traces/${trace.traceId}`, | ||
"logging.googleapis.com/spanId": trace.parentId, | ||
"logging.googleapis.com/trace_sampled": trace.isSampled, | ||
}; | ||
} | ||
|
||
// TODO: This is a copy of exp-logger, implement this | ||
// export function buildLogger(opts: SomeType) { | ||
// return pino({ opts, mixin: getLoggingTraceData }); | ||
// } | ||
|
||
// function severity(label) { | ||
// switch (label) { | ||
// case "trace": | ||
// return "DEBUG"; | ||
// case "debug": | ||
// return "DEBUG"; | ||
// case "info": | ||
// return "INFO"; | ||
// case "warn": | ||
// return "WARNING"; | ||
// case "error": | ||
// return "ERROR"; | ||
// case "fatal": | ||
// return "CRITICAL"; | ||
// default: | ||
// return "DEFAULT"; | ||
// } | ||
// } | ||
|
||
// /** | ||
// * @typedef LoggerOptions | ||
// * @property {string} options.logLevel="info" which level of severity to log at | ||
// * @property {function} options.mixin mixin for additional information in the log statement | ||
// * @property {function} [options.formatLog] function to do change the shape of the log object | ||
// */ | ||
|
||
// /** @typedef {import("pino").Logger} Logger */ | ||
|
||
// /** | ||
// * @param {LoggerOptions} options | ||
// * @return {Logger} the logger. | ||
// * | ||
// */ | ||
// function init(options) { | ||
// const env = process.env.NODE_ENV || "development"; | ||
// const shouldPrettyPrint = ["development", "test", "dev"].includes(env); | ||
|
||
// const logLocation = env === "test" && "./logs/test.log"; | ||
// return pino({ | ||
// level: options?.logLevel ?? "info", | ||
// messageKey: "message", | ||
// base: undefined, | ||
// formatters: { | ||
// level(label) { | ||
// if (shouldPrettyPrint) { | ||
// return { level: label }; | ||
// } | ||
// return { severity: severity(label) }; | ||
// }, | ||
// ...(options?.formatLog && { log: options?.formatLog }), | ||
// }, | ||
// timestamp: () => `,"time": "${new Date().toISOString()}"`, | ||
// transport: shouldPrettyPrint | ||
// ? { | ||
// target: "pino-pretty", | ||
// options: { | ||
// destination: logLocation || 1, | ||
// colorize: !logLocation, | ||
// messageKey: "message", | ||
// }, | ||
// } | ||
// : undefined, | ||
// mixin: options?.mixin, | ||
// }); | ||
// } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import type { RequestHandler } from "express"; | ||
import { AsyncLocalStorage } from "node:async_hooks"; | ||
|
||
type Store = { | ||
traceparent?: string; | ||
clientServiceAccount?: string; | ||
[key: string]: unknown; | ||
}; | ||
|
||
const storage = new AsyncLocalStorage<Store>(); | ||
|
||
export const middleware: RequestHandler = (req, _res, next) => { | ||
const traceparent = req.header("traceparent"); | ||
|
||
storage.run({ traceparent }, () => { | ||
next(); | ||
}); | ||
}; | ||
|
||
export function getStore() { | ||
return storage.getStore() || {}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/** | ||
* Traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00 | ||
* | ||
* base16(version) = 00 | ||
* base16(trace-id) = 4bf92f3577b34da6a3ce929d0e0e4736 | ||
* base16(parent-id) = 00f067aa0ba902b7 | ||
* base16(trace-flags) = 00 // 00 is not sampled, 01 is sampled | ||
*/ | ||
export function getTraceFromTraceparent(traceHeader: string) { | ||
const parts = traceHeader.split("-"); | ||
|
||
if (!parts || parts.length !== 4) return; | ||
|
||
return { | ||
traceId: parts[1], | ||
parentId: parts[2], | ||
isSampled: parts[3] !== "00", | ||
}; | ||
} |
Oops, something went wrong.