-
Notifications
You must be signed in to change notification settings - Fork 227
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
feat(azure-functions): support Azure Functions programming model v4 #4426
base: main
Are you sure you want to change the base?
Conversation
See https://learn.microsoft.com/en-ca/azure/azure-functions/functions-node-upgrade-v4 This builds on the work in #4178 by @qzxlkj (type that 5 times fast), which provide most of the runtime code fix. The rest of this is adding testing and updated examples and docs. Refs: #4178 Closes: #3185
tl;dr: Distributed tracing for incoming requests to Azure Functions using their Node.js programming model v4 does not work. This is due to a bug in Azure Functions that results in distributed tracing issues with Azure FunctionsAzure Functions currently has behaviour that breaks distributed tracing. The following describes the behaviour with no Instrumentation of Azure Functions is done via the invocation hooks mechanism. The
See the following for this issue having been reported: optionsTo cope with this at least partly-unusable trace-context: First, this instrumentation prefers to directly use the trace-context from the incoming HTTP headers, if any. (Dev Note: Future work could possibly monkey-patch Option A: use
|
For the record, though we are not using it, this is how Option A above is implemented: % diff -u azure-functions.js azure-functions.js.option-a
--- azure-functions.js 2025-01-16 13:31:47
+++ azure-functions.js.option-a 2025-01-16 13:31:34
@@ -423,6 +423,14 @@
log.trace(
{ traceparent, tracestate },
'azure-functions: get trace-context from HTTP trigger request headers',
+ );
+ }
+ if (!traceparent && context?.traceContext?.traceParent) {
+ traceparent = context.traceContext.traceParent;
+ tracestate = context.traceContext.traceState;
+ log.trace(
+ { traceparent, tracestate },
+ 'azure-functions: get trace-context from invocationContext.traceContext',
);
} |
Also for the posterity, this is what the azfunc example looked like when the "Hi" function called the "Bye" function before returning: const { app } = require('@azure/functions');
app.http('Hi', {
methods: ['GET'],
authLevel: 'anonymous',
handler: async (request, _context) => {
// Call `GET /api/Bye` on this same Azure Function.
const url = new URL(request.url);
url.pathname = '/api/Bye';
const byeRes = await fetch(url);
const byeBody = await byeRes.json();
const body = JSON.stringify({
hi: 'there',
'from /api/Bye call': byeBody
});
return {
status: 200,
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(body)
},
body
};
},
}); |
Some screenshots of tracing data from requests to the example app deployed to Azure:
Here the HTTP request made inside the Azure Function timed out. |
…rsions; the ~4 was the AF 'runtime version' of which there is only v4 currently
if (triggerType === TRIGGER_HTTP && context.req && context.req.headers) { | ||
traceparent = | ||
context.req.headers.traceparent || | ||
context.req.headers['elastic-apm-traceparent']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewer note: I'm also dropping support for the now long-ancient 'elastic-apm-traceparent' header. This is obsolete.
functionName: context.functionName, | ||
}; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Credit: this block is directly from #4178
This is the bulk of the fix for supporting Azure Functions v4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewer note: This is a direct copy of some of the functions that were in azure-functions.test.js before it was broken into two separate test files for v3 and v4.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewer note: Testing azure functions involves npm install
ing the ridiculously large azure-functions-core-tools
dep. To limit the insanity I've limited testing of v3 to Node.js 18 and v4 to Node.js 20.
@@ -168,7 +52,7 @@ function checkExpectedApmEvents(t, apmEvents) { | |||
if (apmEvents.length > 0) { | |||
const metadata = apmEvents.shift().metadata; | |||
t.ok(metadata, 'metadata is first event'); | |||
t.equal(metadata.service.name, 'AJsAzureFnApp', 'metadata.service.name'); | |||
t.equal(metadata.service.name, 'azfunc3', 'metadata.service.name'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewer note: This and all the remaining diffs in this file are from renaming the fixture: s/AJsAzureFnApp/azfunc3/.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewer note: This file is an almost exact copy of azure-functions-v3.test.js, except it tests the separate fixtures/azfunc4, and it doesn't test as many scenarios/edge cases because I didn't think that is worth a day or two of added test writing at this point.
There could likely be more code sharing between these two files, but again, I didn't want to blow too much time perfecting this.
See https://learn.microsoft.com/en-ca/azure/azure-functions/functions-node-upgrade-v4
This builds on the work in #4178
by @qzxlkj (type that 5 times fast), which provides most of the runtime code fix.
The rest of this is adding testing and updated examples and docs.
Refs: #4178
Closes: #3185
checklist