Skip to content

Commit c86ef77

Browse files
authored
feat: change to batch processor (#326)
* feat: change to batch exporter * feat: add spanProcessorFactory * feat: further usage of spanProcessorFactory * docs: add performance note * feat: more usage of spanProcessorFactory * docs: remove unused code * feat: more spanProcessorFactory usage * fix: lower scheduledDelayMillis * feat: more usage of spanProcessorFactory * feat: more spanProcessorFactory usage * feat: add test using the BatchSpanProcessor * docs: *
1 parent e3d02c0 commit c86ef77

File tree

20 files changed

+179
-12
lines changed

20 files changed

+179
-12
lines changed

apps/backend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@graphql-debugger/graphql-schema": "workspace:^",
2424
"@graphql-debugger/plugin-express": "workspace:^",
2525
"@graphql-debugger/ui": "workspace:^",
26+
"@graphql-debugger/opentelemetry": "workspace:^",
2627
"@graphql-debugger/utils": "workspace:^",
2728
"cors": "2.8.5",
2829
"express": "4.19.2",

apps/backend/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { DebuggerClient } from "@graphql-debugger/client";
22
import { createServer } from "@graphql-debugger/graphql-schema";
3+
import { SpanExporter, SpanProcessor } from "@graphql-debugger/opentelemetry";
34
import { graphqlDebugger } from "@graphql-debugger/plugin-express";
45

56
import cors from "cors";
@@ -14,9 +15,11 @@ import { debug } from "./debug";
1415
export async function start({
1516
port,
1617
client,
18+
spanProcessorFactory,
1719
}: {
1820
port: string;
1921
client: DebuggerClient;
22+
spanProcessorFactory?: (exporter: SpanExporter) => SpanProcessor;
2023
}) {
2124
try {
2225
const app: Express = express();
@@ -29,6 +32,7 @@ export async function start({
2932
"/graphql",
3033
createServer({
3134
client,
35+
spanProcessorFactory,
3236
}),
3337
);
3438
app.use(

apps/backend/src/main.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
1+
import {
2+
SimpleSpanProcessor,
3+
SpanExporter,
4+
} from "@graphql-debugger/opentelemetry";
5+
16
import { client } from "./client";
27
import { BACKEND_PORT } from "./config";
38
import { debug } from "./debug";
49
import { start } from "./index";
510

6-
start({ port: BACKEND_PORT, client })
11+
const spanProcessorFactory =
12+
process.env.NODE_ENV === "development"
13+
? (exporter: SpanExporter) => new SimpleSpanProcessor(exporter)
14+
: undefined;
15+
16+
start({ port: BACKEND_PORT, client, spanProcessorFactory })
717
.then(() => {
818
debug("Online");
919
})

docs/src/pages/docs/_meta.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export default {
22
index: "Quick Start",
33
why: "Why Debugger ?",
44
how: "How Debugger Works ?",
5+
performance: "Performance",
56
components: "Components",
67
packages: "Packages",
78
plugins: "Plugins",
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# GraphQL Debugger Performance
2+
3+
We use standard OpenTelemetry libraries in our implementation to ensure that our tool does not introduce any performance overhead. We accept there to be minor overhead from our implementation as we add additional instrumentation to the server. We work hard to ensure GraphQL Debuggers performance does not impact the performance of your server.
4+
5+
## Benchmarks
6+
7+
We have public benchmarks executed on each commit to ensure that we are not introduce any performance regressions. You can find the benchmarks in our monorepo under the `benchmarks` directory.
8+
9+
1. https://github.com/rocket-connect/graphql-debugger/tree/main/benchmarks
10+
11+
> We collaborate with the OpenTelemetry community to ensure that our implementation is as performant as possible see https://github.com/open-telemetry/opentelemetry-js/issues/4741
12+
13+
## What does GraphQL Debugger instrument?
14+
15+
GraphQL Debugger wraps each field resolver in your GraphQL schema with a span. It does this by visiting the AST at startup and adding the [`@trace` directive](/docs/packages/trace-directive) to each field. Each span is then generated using the OpenTelemetry API.
16+
17+
On span creation we capture various attributes of the field resolver. This could include, the GraphQL query, the arguments passed to the field resolver, the result of the field resolver, and the time it took to execute the field resolver.
18+
19+
## How can this impact performance?
20+
21+
Adding more function calls to your stack is always going to have some impact on performance. We work hard to ensure that the impact is minimal. We have a number of optimizations in place to ensure that the impact is minimal. You can read more about these optimizations in our [Performance Issue](https://github.com/rocket-connect/graphql-debugger/issues/322).

e2e/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"@graphql-debugger/client": "workspace:^",
2727
"@graphql-debugger/collector-proxy": "workspace:^",
2828
"@graphql-debugger/trace-schema": "workspace:^",
29+
"@graphql-debugger/opentelemetry": "workspace:^",
2930
"@graphql-debugger/ui": "workspace:^",
3031
"@graphql-debugger/utils": "workspace:^",
3132
"@graphql-tools/schema": "10.0.3",

e2e/tests/utils/backend.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as backend from "@graphql-debugger/backend";
22
import * as collector from "@graphql-debugger/collector-proxy";
3+
import { SimpleSpanProcessor } from "@graphql-debugger/opentelemetry";
34

45
import http from "http";
56

@@ -18,6 +19,7 @@ export async function listen() {
1819
backendServer = await backend.start({
1920
port: backend.BACKEND_PORT,
2021
client: localClient,
22+
spanProcessorFactory: (exporter) => new SimpleSpanProcessor(exporter),
2123
});
2224
const collectorInstance = await collector.start({
2325
port: collector.COLLECTOR_PORT,

e2e/tests/utils/create-test-schema.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { DebuggerClient } from "@graphql-debugger/client";
2+
import { SimpleSpanProcessor } from "@graphql-debugger/opentelemetry";
23
import { traceSchema } from "@graphql-debugger/trace-schema";
34
import { Schema } from "@graphql-debugger/types";
45

@@ -65,6 +66,7 @@ export async function createTestSchema({
6566
const { schema, schemaHash } = traceSchema({
6667
schema: executableSchema,
6768
adapter: client.adapter,
69+
spanProcessorFactory: (exporter) => new SimpleSpanProcessor(exporter),
6870
});
6971

7072
const dbSchema = await client.schema.upsert({

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.0.0-alpha.109",
44
"private": true,
55
"scripts": {
6-
"dev": "cross-env turbo dev --filter '!graphql-debugger' --filter '!@graphql-debugger/landing-page-app' --filter '!@graphql-debugger/landing-page-server' --concurrency=30",
6+
"dev": "cross-env NODE_ENV=\"development\" turbo dev --filter '!graphql-debugger' --filter '!@graphql-debugger/landing-page-app' --filter '!@graphql-debugger/landing-page-server' --concurrency=30",
77
"build": "turbo build",
88
"release": "cross-env DEBUG=\"@graphql-debugger:*\" node ./packages/utils/build/release.js",
99
"test:sequential": "pnpm recursive exec -- sh -c 'pnpm run test || (echo \"Tests failed!\" && exit 1)'",

packages/graphql-schema/src/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import { DebuggerClient } from "@graphql-debugger/client";
2+
import { TraceSchemaInput } from "@graphql-debugger/trace-schema";
23

34
import { createYoga } from "graphql-yoga";
45

56
import { context } from "./context";
67
import { createSchema } from "./schema";
78

8-
export function createServer({ client }: { client: DebuggerClient }) {
9-
const { schema, schemaHash } = createSchema({ client });
9+
export function createServer({
10+
client,
11+
spanProcessorFactory,
12+
}: {
13+
client: DebuggerClient;
14+
spanProcessorFactory?: TraceSchemaInput["spanProcessorFactory"];
15+
}) {
16+
const { schema, schemaHash } = createSchema({ client, spanProcessorFactory });
1017

1118
return createYoga({
1219
schema,

0 commit comments

Comments
 (0)