Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OTEL support for RPC functions in vanilla CF worker #177

Open
asharirfan opened this issue Oct 25, 2024 · 3 comments
Open

OTEL support for RPC functions in vanilla CF worker #177

asharirfan opened this issue Oct 25, 2024 · 3 comments

Comments

@asharirfan
Copy link

Hey,

I am trying to setup OTEL on a vanilla worker with a simple RPC function. But just found out that the support for this implementation is missing from the package.

Opening this issue to track the progress of the support.

Code Snippet

Here is a simple code snippet:

import {instrument, ResolveConfigFn} from '@microlabs/otel-cf-workers';
import {trace} from '@opentelemetry/api';

interface Env {
    TRACING: string;
    ENVIRONMENT: string;
}

const tracer = trace.getTracer('worker');

const handler = {
    myRPCFunction() {
        const span = tracer.startSpan('myRPCFunction');
                span.end();
                return true;
    },
};

const config: ResolveConfigFn = (env: Env) => {
    return {
        exporter: {
            url: 'https://api.axiom.co/v1/traces',
            headers: {
                Authorization: `Bearer ${env.TRACING}`,
                'X-Axiom-Dataset': `tracing_${env.ENVIRONMENT}`, // Axiom dataset name for OpenTelemetry
            },
        },
        service: {name: 'service-name'}, // OpenTelemetry service name
    };
};
export default instrument(handler, config);

Cheers!

@wesleyakio
Copy link

@evanderkoogh Are there any short term plans for this? If not, I could try to take a swing at it. For that would be interesting to hear your thought on:

  • I couldn't find any docs on collaborating, do you have any specific requirements or rules?
  • Is there interest in having this as part of the library?
  • Do you see this being implemented in any specific way? (same as instrumentDO or something different?)
  • What metrics would you like to see before merging?

@evanderkoogh
Copy link
Owner

Hey @wesleyakio, great point on a doc for collaboration, will get around to that. There aren't a ton of rules or requirements to be honest, but even that is worth explaining right?

There is absolute interest in getting everything CF supplies supported by this library..

And while I absolutely would love for you to take a crack at it, I am right in the middle of a complete rewrite of the core logic behind handling the flow of a request to a) make it more robust, but more importantly b) much much easier to instrument new features like RPC.

The core logic itself is finished in the core-logic-rewrite branch, and implemented for fetch, but I still have to migrate over all of the existing handlers (queue, scheduled, do.. etc).

Hopefully I'll get that done this week or next at the latest and I'll merge that in.

So if you want to get started, I would start from https://github.com/evanderkoogh/otel-cf-workers/tree/core-logic-refactor and look at the way the fetch handler is instrumented (

export const fetchInstrumentation: HandlerInstrumentation<Request, OrPromise<Response>> = {
getInitialSpanInfo: (request) => {
const spanContext = getParentContextFromRequest(request)
const attributes = {
['faas.trigger']: 'http',
['faas.invocation_id']: request.headers.get('cf-ray') ?? undefined,
}
Object.assign(attributes, gatherRequestAttributes(request))
Object.assign(attributes, gatherIncomingCfAttributes(request))
const method = request.method.toUpperCase()
return {
name: `fetchHandler ${method}`,
options: {
attributes,
kind: SpanKind.SERVER,
},
context: spanContext,
}
},
getAttributesFromResult: (response) => {
return gatherResponseAttributes(response)
},
runFinally: (span, request) => {
const readable = span as unknown as ReadableSpan
if (readable.attributes['http.route']) {
const method = request.method.toUpperCase()
span.updateName(`${method} ${readable.attributes['http.route']}`)
}
return span
},
}
)

That is for the handler side, the stub side of things should be relatively similar to the DO one I would imagine.

Now the one challenge is probably how we are going to be doing trace context propagration, but that is also something that we can defer until we have an initial working version.

Also happy to jump on a call at some point and walk you through bits of the API and get you pointed in the right direction if that would help you :)

@wesleyakio
Copy link

wesleyakio commented Dec 4, 2024

Hey @evanderkoogh, thank you for your answer. I've changed focus to another project but should be back to this one in a week or so. I'll reach out to you again to check status and possibly coordinate next steps.

Meanwhile... I gave some thought to the trace context problem and I don't really see any good options here without changes to the host app code. I have a couple of hackish ideas I want to test that might get around the code modification requirement but they all add an extra roundtrip. Not a problem for a worker running close, but if one of them has smart placement enabled then we could be running far apart and that extra roundtrip becomes costly. (Smart placement is not currently supported for RPC so could we ignore the performance penalty until the feature comes perhaps?)

It would be nice if Cloudflare suddenly appeared in the thread and exposed a hidden context being shared under the hood somehow 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants