Skip to content

Commit

Permalink
Merge branch 'main' into tracing_otel_yeah
Browse files Browse the repository at this point in the history
  • Loading branch information
hatchan committed Jul 23, 2024
2 parents 297d79e + 3ab1ba3 commit 184a1ee
Show file tree
Hide file tree
Showing 21 changed files with 9,215 additions and 5,946 deletions.
45 changes: 22 additions & 23 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions api/.npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ node_modules
# do not publish src
src/*

# do not publish .neon if it exists
.neon

# do not publish test config
vitest.config.ts

# do not publish playground scripts that are just useful for testing things
test-content/*
scripts/*
Expand Down
8 changes: 8 additions & 0 deletions api/bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,14 @@ function getFallbackServiceTarget() {
*/
function findEnvVarFile() {
const envFiles = [".dev.vars", ".env.local", ".env.dev", ".env"];
// To support monorepos, first look in current working directory for one of the common env files
for (const file of envFiles) {
const filePath = path.join(process.cwd(), file);
if (fs.existsSync(filePath)) {
return filePath;
}
}
// Then, check the project root!
for (const file of envFiles) {
const filePath = path.join(PROJECT_ROOT_DIR, file);
if (fs.existsSync(filePath)) {
Expand Down
2 changes: 1 addition & 1 deletion client-library/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"author": "Fiberplane<[email protected]>",
"type": "module",
"main": "dist/index.js",
"version": "0.2.0",
"version": "0.2.1-beta.4",
"dependencies": {
"@neondatabase/serverless": "^0.9.3"
},
Expand Down
24 changes: 14 additions & 10 deletions client-library/src/honoMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { env } from "hono/adapter";
import { createMiddleware } from "hono/factory";
import { replaceFetch } from "./replace-fetch";
import { RECORDED_CONSOLE_METHODS, log } from "./request-logger";

import { replaceFetch } from "./replace-fetch.js";
import { RECORDED_CONSOLE_METHODS, log } from "./request-logger.js";
import {
errorToJson,
extractCallerLocation,
generateUUID,
polyfillWaitUntil,
getRuntimeContext,
shouldIgnoreFpxLog,
shouldPrettifyFpxLog,
specialFormatMessage,
tryCreateFriendlyLink,
tryPrettyPrintLoggerLog,
} from "./utils";
} from "./utils.js";

// Type hack that makes our middleware types play nicely with Hono types
type RouterRoute = {
Expand Down Expand Up @@ -94,7 +95,7 @@ export function createHonoMiddleware<App extends HonoApp>(

const service = env<FpxEnv>(c).FPX_SERVICE_NAME || "unknown";

const ctx = c.executionCtx;
const executionCtx = getRuntimeContext(c);

if (!app) {
// Logging here before we patch the console.* methods so we don't cause trouble
Expand All @@ -103,10 +104,6 @@ export function createHonoMiddleware<App extends HonoApp>(
);
}

// NOTE - Polyfilling `waitUntil` is probably not necessary for Cloudflare workers, but could be good for vercel envs
// https://github.com/highlight/highlight/pull/6480
polyfillWaitUntil(ctx);

const teardownFunctions: Array<() => void> = [];

const { originalFetch, undo: undoReplaceFetch } = replaceFetch({
Expand All @@ -119,6 +116,8 @@ export function createHonoMiddleware<App extends HonoApp>(
// NOTE - Take the traceId from headers but then fall back to uuid here
const traceId = c.req.header("x-fpx-trace-id") || generateUUID();

const originalConsoleError = console.error;

// We monkeypatch `console.*` methods because it's the only way to send consumable logs locally without setting up an otel colletor
for (const level of RECORDED_CONSOLE_METHODS) {
const originalConsoleMethod = console[level];
Expand Down Expand Up @@ -175,14 +174,19 @@ export function createHonoMiddleware<App extends HonoApp>(
headers.append("x-Fpx-Route-Inspector", "enabled");
}

ctx.waitUntil(
executionCtx.waitUntil(
// Use `originalFetch` to avoid an infinite loop of logging to FPX
// If we use our monkeyPatched version, then each fetch logs to FPX,
// which triggers another fetch to log to FPX, etc.
originalFetch(endpoint, {
method: "POST",
headers,
body: JSON.stringify(payload),
}).catch((error) => {
// NOTE - We handle errors here to avoid crashing the client runtime
if (libraryDebugMode) {
originalConsoleError("Failed to send telemetry data:", error);
}
}),
);

Expand Down
2 changes: 1 addition & 1 deletion client-library/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { createHonoMiddleware } from "./honoMiddleware";
export { createHonoMiddleware } from "./honoMiddleware.js";
2 changes: 1 addition & 1 deletion client-library/src/replace-fetch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IGNORE_FPX_LOGGER_LOG, errorToJson, generateUUID } from "./utils";
import { IGNORE_FPX_LOGGER_LOG, errorToJson, generateUUID } from "./utils.js";

/**
* Hacky function that monkey-patches fetch to send data about network requests to fpx.
Expand Down
2 changes: 1 addition & 1 deletion client-library/src/request-logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const RECORDED_CONSOLE_METHODS = [
"warn",
] as const;

import { PRETTIFY_FPX_LOGGER_LOG, type PrintFunc } from "./utils";
import { PRETTIFY_FPX_LOGGER_LOG, type PrintFunc } from "./utils.js";

// === LOGGER FUNCTION === //
function logReq(
Expand Down
47 changes: 45 additions & 2 deletions client-library/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import type { NeonDbError } from "@neondatabase/serverless";
import type { Context } from "hono";
import { getRuntimeKey } from "hono/adapter";

// HACK - We inject this symbol in our request/response logger in order to skip logging massive payloads
export const PRETTIFY_FPX_LOGGER_LOG = Symbol("PRETTIFY_FPX_LOGGER_LOG");
// HACK - We inject this symbol in our request/response logger to avoid infintie loop of logging on fetches
export const IGNORE_FPX_LOGGER_LOG = Symbol("IGNORE_FPX_LOGGER_LOG");

export type ExtendedExecutionContext = ExecutionContext & {
type WaitUntilable = Pick<ExecutionContext, "waitUntil">;

export type ExtendedExecutionContext = WaitUntilable & {
__waitUntilTimer?: ReturnType<typeof setInterval>;
__waitUntilPromises?: Promise<void>[];
waitUntilFinished?: () => Promise<void>;
Expand Down Expand Up @@ -100,7 +104,14 @@ export function neonDbErrorToJson(error: NeonDbError) {
// internalQuery: error?.sourceError?.internalQuery,
};
}
export function polyfillWaitUntil(ctx: ExtendedExecutionContext) {

/**
* Polyfill for `waitUntil` in non-Cloudflare environments
*
* This will be more important when we support OTEL.
* See: https://github.com/highlight/highlight/pull/6480
*/
function polyfillWaitUntil(ctx: ExtendedExecutionContext) {
if (typeof ctx.waitUntil !== "function") {
if (!Array.isArray(ctx.__waitUntilPromises)) {
ctx.__waitUntilPromises = [];
Expand All @@ -120,13 +131,45 @@ export function polyfillWaitUntil(ctx: ExtendedExecutionContext) {
};
}

// NOTE - We do not make use of this here, but it could be helpful for OTEL
// Highlight uses this in `consumeAndFlush` for errors
// See: sdk/highlight-next/src/util/with-highlight-edge.ts
// In the following PR:
// https://github.com/highlight/highlight/pull/6480/files#diff-5a425baa46cb0362f4f233565c28ad4b43c8fa8274ef38f14f2c56d526b35b23R39
ctx.waitUntilFinished = async function waitUntilFinished() {
if (ctx.__waitUntilPromises) {
await Promise.allSettled(ctx.__waitUntilPromises);
}
};
}

function isCloudflareRuntime() {
return getRuntimeKey() === "workerd";
}

/**
* Runtime-safe way of accessing `executionCtx`
*
* At the time of writing, `executionCtx` is not available in all runtimes,
* and we need to provide a polyfill for non-Cloudflare environments.
* Otherwise, we get a runtime error in Node, Deno, etc.
*
* In the future, we should use different middleware for different runtimes.
*/
export function getRuntimeContext(c: Context): ExtendedExecutionContext {
if (isCloudflareRuntime()) {
return c.executionCtx as ExtendedExecutionContext;
}

// HACK - This is the polyfill for waitUntil
// I'm not entirely sure if this will lead to a memory leak in certain runtimes,
// since each request will get its own execution context,
// and it's not clear to me that this object will be garbage collected after all of its promises resolve
const fakeCtx = {} as WaitUntilable;
polyfillWaitUntil(fakeCtx);
return fakeCtx;
}

/**
* Quick and dirty uuid utility
*/
Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@radix-ui/react-toast": "^1.2.1",
"@radix-ui/react-tooltip": "^1.0.7",
"@tanstack/react-table": "^8.17.3",
"@tanstack/react-query": "^5.51.1",
"@types/highlight-words-core": "^1.2.3",
"@uiw/codemirror-theme-duotone": "^4.22.2",
"@uiw/react-codemirror": "^4.22.2",
Expand All @@ -51,7 +52,6 @@
"react-hook-form": "^7.52.0",
"react-hotkeys-hook": "^4.5.0",
"react-markdown": "^9.0.1",
"react-query": "^3.39.3",
"react-resizable": "^3.0.5",
"react-router-dom": "^6.23.1",
"stopword": "^3.0.1",
Expand Down
9 changes: 4 additions & 5 deletions frontend/src/hooks/useRequestDetails.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { useMizuTraces } from "@/queries";
import { isError } from "react-query";

export function useRequestDetails(traceId?: string) {
const query = useMizuTraces();
const trace = traceId ? query.data?.find((t) => t.id === traceId) : undefined;
const { isPending, isError, data } = useMizuTraces();
const trace = traceId ? data?.find((t) => t.id === traceId) : undefined;
return {
isLoading: query.isLoading,
isError: isError(query),
isPending,
isError,
trace,
};
}
4 changes: 2 additions & 2 deletions frontend/src/hooks/useWebsocketQueryInvalidation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MIZU_TRACES_KEY, PROBED_ROUTES_KEY } from "@/queries";
import { useQueryClient } from "@tanstack/react-query";
import { useEffect } from "react";
import { useQueryClient } from "react-query";
import z from "zod";

/**
Expand Down Expand Up @@ -45,7 +45,7 @@ export function useWebsocketQueryInvalidation() {
);
return;
}
queryClient.invalidateQueries(...decodedAction.payload);
queryClient.invalidateQueries({ queryKey: decodedAction.payload });
};

socket.onclose = (ev) => {
Expand Down
Loading

0 comments on commit 184a1ee

Please sign in to comment.