-
Notifications
You must be signed in to change notification settings - Fork 309
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Plugin for @azure/functions (#4716)
* adds azure functions plugin * adds azure_functions plugin to API documentation * add typescript test for azure functions plugin * adds integration test for azure-functions plugin * add licenses for added dev packages * add azure-functions plugin to github workflow * use pipe for azure-functions integration test child process * update azure-functions integration test api route * refactor azure-functions integration test * add azure func command to path * remove yarn.lock file from azure-functions integration test * allow span kind to be server for azure functions * Update index.d.ts Co-authored-by: Roch Devost <roch.devost@datadoghq.com> * add serverless util * use built in url parser * remove serverless logic from web util * remove wait-on dependency * remove find-process dependency * Revert "remove find-process dependency" This reverts commit 3c004c5. * call func start directly and remove find-process dependency * simplify serverless util * Revert "simplify serverless util" This reverts commit 91a2dd9. * simplify serverless util --------- Co-authored-by: Roch Devost <roch.devost@datadoghq.com>
- Loading branch information
1 parent
ce0bdce
commit 5a113b2
Showing
24 changed files
with
612 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
declare const types: { | ||
HTTP: 'http' | ||
SERVERLESS: 'serverless' | ||
WEB: 'web' | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,5 +2,6 @@ | |
|
||
module.exports = { | ||
HTTP: 'http', | ||
SERVERLESS: 'serverless', | ||
WEB: 'web' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
'use strict' | ||
|
||
const { | ||
addHook | ||
} = require('./helpers/instrument') | ||
const shimmer = require('../../datadog-shimmer') | ||
const dc = require('dc-polyfill') | ||
|
||
const azureFunctionsChannel = dc.tracingChannel('datadog:azure-functions:invoke') | ||
|
||
addHook({ name: '@azure/functions', versions: ['>=4'] }, azureFunction => { | ||
const { app } = azureFunction | ||
|
||
shimmer.wrap(app, 'deleteRequest', wrapHandler) | ||
shimmer.wrap(app, 'http', wrapHandler) | ||
shimmer.wrap(app, 'get', wrapHandler) | ||
shimmer.wrap(app, 'patch', wrapHandler) | ||
shimmer.wrap(app, 'post', wrapHandler) | ||
shimmer.wrap(app, 'put', wrapHandler) | ||
|
||
return azureFunction | ||
}) | ||
|
||
// The http methods are overloaded so we need to check which type of argument was passed in order to wrap the handler | ||
// The arguments are either an object with a handler property or the handler function itself | ||
function wrapHandler (method) { | ||
return function (name, arg) { | ||
if (typeof arg === 'object' && arg.hasOwnProperty('handler')) { | ||
const options = arg | ||
shimmer.wrap(options, 'handler', handler => traceHandler(handler, name, method.name)) | ||
} else if (typeof arg === 'function') { | ||
const handler = arg | ||
arguments[1] = shimmer.wrapFunction(handler, handler => traceHandler(handler, name, method.name)) | ||
} | ||
return method.apply(this, arguments) | ||
} | ||
} | ||
|
||
function traceHandler (handler, functionName, methodName) { | ||
return function (...args) { | ||
const httpRequest = args[0] | ||
const invocationContext = args[1] | ||
return azureFunctionsChannel.tracePromise( | ||
handler, | ||
{ functionName, httpRequest, invocationContext, methodName }, | ||
this, ...args) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
'use strict' | ||
|
||
const TracingPlugin = require('../../dd-trace/src/plugins/tracing') | ||
const { storage } = require('../../datadog-core') | ||
const serverless = require('../../dd-trace/src/plugins/util/serverless') | ||
const web = require('../../dd-trace/src/plugins/util/web') | ||
|
||
const triggerMap = { | ||
deleteRequest: 'Http', | ||
http: 'Http', | ||
get: 'Http', | ||
patch: 'Http', | ||
post: 'Http', | ||
put: 'Http' | ||
} | ||
|
||
class AzureFunctionsPlugin extends TracingPlugin { | ||
static get id () { return 'azure-functions' } | ||
static get operation () { return 'invoke' } | ||
static get kind () { return 'server' } | ||
static get type () { return 'serverless' } | ||
|
||
static get prefix () { return 'tracing:datadog:azure-functions:invoke' } | ||
|
||
bindStart (ctx) { | ||
const { functionName, methodName } = ctx | ||
const store = storage.getStore() | ||
|
||
const span = this.startSpan(this.operationName(), { | ||
service: this.serviceName(), | ||
type: 'serverless', | ||
meta: { | ||
'aas.function.name': functionName, | ||
'aas.function.trigger': mapTriggerTag(methodName) | ||
} | ||
}, false) | ||
|
||
ctx.span = span | ||
ctx.parentStore = store | ||
ctx.currentStore = { ...store, span } | ||
|
||
return ctx.currentStore | ||
} | ||
|
||
error (ctx) { | ||
this.addError(ctx.error) | ||
ctx.currentStore.span.setTag('error.message', ctx.error) | ||
} | ||
|
||
asyncEnd (ctx) { | ||
const { httpRequest, result = {} } = ctx | ||
const path = (new URL(httpRequest.url)).pathname | ||
const req = { | ||
method: httpRequest.method, | ||
headers: Object.fromEntries(httpRequest.headers.entries()), | ||
url: path | ||
} | ||
|
||
const context = web.patch(req) | ||
context.config = this.config | ||
context.paths = [path] | ||
context.res = { statusCode: result.status } | ||
context.span = ctx.currentStore.span | ||
|
||
serverless.finishSpan(context) | ||
} | ||
|
||
configure (config) { | ||
return super.configure(web.normalizeConfig(config)) | ||
} | ||
} | ||
|
||
function mapTriggerTag (methodName) { | ||
return triggerMap[methodName] || 'Unknown' | ||
} | ||
|
||
module.exports = AzureFunctionsPlugin |
100 changes: 100 additions & 0 deletions
100
packages/datadog-plugin-azure-functions/test/integration-test/client.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
'use strict' | ||
|
||
const { | ||
FakeAgent, | ||
hookFile, | ||
createSandbox, | ||
curlAndAssertMessage | ||
} = require('../../../../integration-tests/helpers') | ||
const { spawn } = require('child_process') | ||
const { assert } = require('chai') | ||
|
||
describe('esm', () => { | ||
let agent | ||
let proc | ||
let sandbox | ||
|
||
withVersions('azure-functions', '@azure/functions', version => { | ||
before(async function () { | ||
this.timeout(50000) | ||
sandbox = await createSandbox([`@azure/functions@${version}`, 'azure-functions-core-tools@4'], false, | ||
['./packages/datadog-plugin-azure-functions/test/integration-test/fixtures/*']) | ||
}) | ||
|
||
after(async function () { | ||
this.timeout(50000) | ||
await sandbox.remove() | ||
}) | ||
|
||
beforeEach(async () => { | ||
agent = await new FakeAgent().start() | ||
}) | ||
|
||
afterEach(async () => { | ||
proc && proc.kill('SIGINT') | ||
await agent.stop() | ||
}) | ||
|
||
it('is instrumented', async () => { | ||
const envArgs = { | ||
PATH: `${sandbox.folder}/node_modules/azure-functions-core-tools/bin:${process.env.PATH}` | ||
} | ||
proc = await spawnPluginIntegrationTestProc(sandbox.folder, 'func', ['start'], agent.port, undefined, envArgs) | ||
|
||
return curlAndAssertMessage(agent, 'http://127.0.0.1:7071/api/httptest', ({ headers, payload }) => { | ||
assert.propertyVal(headers, 'host', `127.0.0.1:${agent.port}`) | ||
assert.isArray(payload) | ||
assert.strictEqual(payload.length, 1) | ||
assert.isArray(payload[0]) | ||
assert.strictEqual(payload[0].length, 1) | ||
assert.propertyVal(payload[0][0], 'name', 'azure-functions.invoke') | ||
}) | ||
}).timeout(50000) | ||
}) | ||
}) | ||
|
||
async function spawnPluginIntegrationTestProc (cwd, command, args, agentPort, stdioHandler, additionalEnvArgs = {}) { | ||
let env = { | ||
NODE_OPTIONS: `--loader=${hookFile}`, | ||
DD_TRACE_AGENT_PORT: agentPort | ||
} | ||
env = { ...env, ...additionalEnvArgs } | ||
return spawnProc(command, args, { | ||
cwd, | ||
env | ||
}, stdioHandler) | ||
} | ||
|
||
function spawnProc (command, args, options = {}, stdioHandler, stderrHandler) { | ||
const proc = spawn(command, args, { ...options, stdio: 'pipe' }) | ||
return new Promise((resolve, reject) => { | ||
proc | ||
.on('error', reject) | ||
.on('exit', code => { | ||
if (code !== 0) { | ||
reject(new Error(`Process exited with status code ${code}.`)) | ||
} | ||
resolve() | ||
}) | ||
|
||
proc.stdout.on('data', data => { | ||
if (stdioHandler) { | ||
stdioHandler(data) | ||
} | ||
// eslint-disable-next-line no-console | ||
if (!options.silent) console.log(data.toString()) | ||
|
||
if (data.toString().includes('http://localhost:7071/api/httptest')) { | ||
resolve(proc) | ||
} | ||
}) | ||
|
||
proc.stderr.on('data', data => { | ||
if (stderrHandler) { | ||
stderrHandler(data) | ||
} | ||
// eslint-disable-next-line no-console | ||
if (!options.silent) console.error(data.toString()) | ||
}) | ||
}) | ||
} |
15 changes: 15 additions & 0 deletions
15
packages/datadog-plugin-azure-functions/test/integration-test/fixtures/host.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"version": "2.0", | ||
"logging": { | ||
"applicationInsights": { | ||
"samplingSettings": { | ||
"isEnabled": true, | ||
"excludedTypes": "Request" | ||
} | ||
} | ||
}, | ||
"extensionBundle": { | ||
"id": "Microsoft.Azure.Functions.ExtensionBundle", | ||
"version": "[4.*, 5.0.0)" | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
packages/datadog-plugin-azure-functions/test/integration-test/fixtures/local.settings.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"IsEncrypted": false, | ||
"Values": { | ||
"FUNCTIONS_WORKER_RUNTIME": "node", | ||
"AzureWebJobsFeatureFlags": "EnableWorkerIndexing", | ||
"AzureWebJobsStorage": "" | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
packages/datadog-plugin-azure-functions/test/integration-test/fixtures/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"name": "azure-function-node-integration-test", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "src/functions/server.mjs", | ||
"scripts": { | ||
"start": "func start" | ||
}, | ||
"dependencies": { | ||
"@azure/functions": "^4.0.0" | ||
}, | ||
"devDependencies": { | ||
"azure-functions-core-tools": "^4.x" | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
...es/datadog-plugin-azure-functions/test/integration-test/fixtures/src/functions/server.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import 'dd-trace/init.js' | ||
import { app } from '@azure/functions' | ||
|
||
async function handlerFunction (request, context) { | ||
return { | ||
status: 200, | ||
body: 'Hello Datadog!' | ||
} | ||
} | ||
|
||
app.http('httptest', { | ||
methods: ['GET'], | ||
authLevel: 'anonymous', | ||
handler: handlerFunction | ||
}) |
Oops, something went wrong.