fix(medusa): Replace default http tracer (#9390)

This commit is contained in:
Adrien de Peretti
2024-09-30 21:17:30 +02:00
committed by GitHub
parent 570c1803f2
commit 9b6d0e9d56
3 changed files with 36 additions and 60 deletions

View File

@@ -180,7 +180,7 @@ function getBodyParserMiddleware(args?: ParserConfigArgs) {
// TODO this router would need a proper rework, but it is out of scope right now // TODO this router would need a proper rework, but it is out of scope right now
class ApiRoutesLoader { export class ApiRoutesLoader {
/** /**
* Map of router path and its descriptor * Map of router path and its descriptor
* @private * @private
@@ -910,27 +910,6 @@ export class RoutesLoader {
*/ */
readonly #sourceDir: string | string[] readonly #sourceDir: string | string[]
static instrument: {
/**
* Instrument middleware function calls by wrapping the original
* middleware handler inside a custom implementation
*/
middleware: (callback: (typeof ApiRoutesLoader)["traceMiddleware"]) => void
/**
* Instrument route handler function calls by wrapping the original
* middleware handler inside a custom implementation
*/
route: (callback: (typeof ApiRoutesLoader)["traceRoute"]) => void
} = {
middleware(callback) {
ApiRoutesLoader.traceMiddleware = callback
},
route(callback) {
ApiRoutesLoader.traceRoute = callback
},
}
constructor({ constructor({
app, app,
activityId, activityId,

View File

@@ -9,7 +9,7 @@ import {
gqlSchemaToTypes, gqlSchemaToTypes,
GracefulShutdownServer, GracefulShutdownServer,
} from "@medusajs/framework/utils" } from "@medusajs/framework/utils"
import http, { IncomingMessage, ServerResponse } from "http" import http from "http"
import { logger } from "@medusajs/framework/logger" import { logger } from "@medusajs/framework/logger"
import loaders from "../loaders" import loaders from "../loaders"
@@ -45,6 +45,13 @@ export async function registerInstrumentation(directory: string) {
} }
} }
/**
* Wrap request handler inside custom implementation to enabled
* instrumentation.
*/
// eslint-disable-next-line no-var
export var traceRequestHandler: (...args: any[]) => Promise<any> = void 0 as any
async function start({ port, directory, types }) { async function start({ port, directory, types }) {
async function internalStart() { async function internalStart() {
track("CLI_START") track("CLI_START")
@@ -53,16 +60,20 @@ async function start({ port, directory, types }) {
const app = express() const app = express()
const http_ = http.createServer(async (req, res) => { const http_ = http.createServer(async (req, res) => {
await start.traceRequestHandler( if (traceRequestHandler) {
async () => { await traceRequestHandler(
return new Promise((resolve) => { async () => {
res.on("finish", resolve) return new Promise((resolve) => {
app(req, res) res.on("finish", resolve)
}) app(req, res)
}, })
req, },
res req,
) res
)
} else {
app(req, res)
}
}) })
try { try {
@@ -123,16 +134,4 @@ async function start({ port, directory, types }) {
await internalStart() await internalStart()
} }
/**
* Wrap request handler inside custom implementation to enabled
* instrumentation.
*/
start.traceRequestHandler = async (
requestHandler: () => Promise<void>,
_: IncomingMessage,
__: ServerResponse
) => {
return await requestHandler()
}
export default start export default start

View File

@@ -1,6 +1,6 @@
import { snakeCase } from "lodash" import { snakeCase } from "lodash"
import { Query } from "@medusajs/framework" import { Query } from "@medusajs/framework"
import { RoutesLoader } from "@medusajs/framework/http" import { ApiRoutesLoader } from "@medusajs/framework/http"
import { Tracer } from "@medusajs/framework/telemetry" import { Tracer } from "@medusajs/framework/telemetry"
import type { SpanExporter } from "@opentelemetry/sdk-trace-node" import type { SpanExporter } from "@opentelemetry/sdk-trace-node"
import type { Instrumentation } from "@opentelemetry/instrumentation" import type { Instrumentation } from "@opentelemetry/instrumentation"
@@ -19,11 +19,11 @@ function shouldExcludeResource(resource: string) {
* OpenTelemetry * OpenTelemetry
*/ */
export function instrumentHttpLayer() { export function instrumentHttpLayer() {
const start = require("../commands/start") const startCommand = require("../commands/start")
const HTTPTracer = new Tracer("@medusajs/http", "2.0.0") const HTTPTracer = new Tracer("@medusajs/http", "2.0.0")
const { SpanStatusCode } = require("@opentelemetry/api") const { SpanStatusCode } = require("@opentelemetry/api")
start.traceRequestHandler = async (requestHandler, req, res) => { startCommand.traceRequestHandler = async (requestHandler, req, res) => {
if (shouldExcludeResource(req.url!)) { if (shouldExcludeResource(req.url!)) {
return await requestHandler() return await requestHandler()
} }
@@ -55,16 +55,14 @@ export function instrumentHttpLayer() {
* Instrumenting the route handler to report traces to * Instrumenting the route handler to report traces to
* OpenTelemetry * OpenTelemetry
*/ */
RoutesLoader.instrument.route((handler) => { ApiRoutesLoader.traceRoute = (handler) => {
const traceName = `route: ${
handler.name ? snakeCase(handler.name) : `anonymous`
}`
return async (req, res) => { return async (req, res) => {
if (shouldExcludeResource(req.originalUrl)) { if (shouldExcludeResource(req.originalUrl)) {
return await handler(req, res) return await handler(req, res)
} }
const traceName = `route: ${req.method} ${req.originalUrl}`
await HTTPTracer.trace(traceName, async (span) => { await HTTPTracer.trace(traceName, async (span) => {
try { try {
await handler(req, res) await handler(req, res)
@@ -79,22 +77,22 @@ export function instrumentHttpLayer() {
} }
}) })
} }
}) }
/** /**
* Instrumenting the middleware handler to report traces to * Instrumenting the middleware handler to report traces to
* OpenTelemetry * OpenTelemetry
*/ */
RoutesLoader.instrument.middleware((handler) => { ApiRoutesLoader.traceMiddleware = (handler) => {
const traceName = `middleware: ${
handler.name ? snakeCase(handler.name) : `anonymous`
}`
return async (req, res, next) => { return async (req, res, next) => {
if (shouldExcludeResource(req.originalUrl)) { if (shouldExcludeResource(req.originalUrl)) {
return handler(req, res, next) return handler(req, res, next)
} }
const traceName = `middleware: ${
handler.name ? snakeCase(handler.name) : `anonymous`
}`
await HTTPTracer.trace(traceName, async (span) => { await HTTPTracer.trace(traceName, async (span) => {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
const _next = (error?: any) => { const _next = (error?: any) => {
@@ -117,7 +115,7 @@ export function instrumentHttpLayer() {
.catch(next) .catch(next)
.then(next) .then(next)
} }
}) }
} }
/** /**