lib/instrumentation/modules/aws-sdk/dynamodb.js (125 lines of code) (raw):

/* * Copyright Elasticsearch B.V. and other contributors where applicable. * Licensed under the BSD 2-Clause License; you may not use this file except in * compliance with the BSD 2-Clause License. */ 'use strict'; const TYPE = 'db'; const SUBTYPE = 'dynamodb'; const ACTION = 'query'; function getRegionFromRequest(request) { return ( request && request.service && request.service.config && request.service.config.region ); } function getPortFromRequest(request) { return ( request && request.service && request.service.endpoint && request.service.endpoint.port ); } function getMethodFromRequest(request) { const method = request && request.operation; if (method) { return method[0].toUpperCase() + method.slice(1); } } function getStatementFromRequest(request) { const method = getMethodFromRequest(request); if ( method === 'Query' && request && request.params && request.params.KeyConditionExpression ) { return request.params.KeyConditionExpression; } return undefined; } function getAddressFromRequest(request) { return ( request && request.service && request.service.endpoint && request.service.endpoint.hostname ); } function getTableFromRequest(request) { const table = request && request.params && request.params.TableName; if (!table) { return ''; } return ` ${table}`; } // Creates the span name from request information function getSpanNameFromRequest(request) { const method = getMethodFromRequest(request); const table = getTableFromRequest(request); const name = `DynamoDB ${method}${table}`; return name; } function shouldIgnoreRequest(request, agent) { return false; } // Main entrypoint for SQS instrumentation // // Must call (or one of its function calls must call) the // `orig` function/method function instrumentationDynamoDb( orig, origArguments, request, AWS, agent, { version, enabled }, ) { if (shouldIgnoreRequest(request, agent)) { return orig.apply(request, origArguments); } const ins = agent._instrumentation; const name = getSpanNameFromRequest(request); const span = ins.createSpan(name, TYPE, SUBTYPE, ACTION, { exitSpan: true }); if (!span) { return orig.apply(request, origArguments); } const region = getRegionFromRequest(request); const dbContext = { type: SUBTYPE, instance: region, }; const dbStatement = getStatementFromRequest(request); if (dbStatement) { dbContext.statement = dbStatement; } span.setDbContext(dbContext); span._setDestinationContext({ address: getAddressFromRequest(request), port: getPortFromRequest(request), cloud: { region, }, }); const onComplete = function (response) { if (response && response.error) { agent.captureError(response.error); } span.end(); }; // Bind onComplete to the span's run context so that `captureError` picks // up the correct currentSpan. const parentRunContext = ins.currRunContext(); const spanRunContext = parentRunContext.enterSpan(span); request.on( 'complete', ins.bindFunctionToRunContext(spanRunContext, onComplete), ); const cb = origArguments[origArguments.length - 1]; if (typeof cb === 'function') { origArguments[origArguments.length - 1] = ins.bindFunctionToRunContext( parentRunContext, cb, ); } return ins.withRunContext(spanRunContext, orig, request, ...origArguments); } module.exports = { instrumentationDynamoDb, // exported for testing getRegionFromRequest, getPortFromRequest, getStatementFromRequest, getAddressFromRequest, getMethodFromRequest, };