Skip to content

Commit fd1e5b2

Browse files
prodion23prodion23
andauthored
Release 1.2.2 (#54)
* Lambda support (#38) * add support for NODE_OPTIONS require flag * Add lambda instrumentation * add layer build files * add update deps, add gitignore for copied package.json * add test * add instructions to build * dont call instrument for awsinstrumentation test * use done in lambda tests * remove instrument call * fix lambda coverage * add cookie capture * feat: lambda layer support * bump minor (#40) Co-authored-by: prodion23 <[email protected]> * feat: bump minor (#42) Co-authored-by: prodion23 <[email protected]> * Pull release back into main * Support plain http server (#44) * feat: bump minor * Use node builtin methods for header capture, add test for node http server * Revert unneeded body capture change * space * add req body test + read Co-authored-by: prodion23 <[email protected]> * Add hapi support (#46) * Add hapi support * Comment original to not affect cov reports or lint rules * Add compat check * tsc * Wrap values in array * Skip hapi test on non-compat node versions * Fix test * Update framework detection * Fix min version check * Force framework check for hapi * Interpolate url into string to produce original url Co-authored-by: prodion23 <[email protected]> * feat: hapi support * Pull release back into main (#48) * feat: bump minor 1.1.0 (#43) * Lambda support (#38) * add support for NODE_OPTIONS require flag * Add lambda instrumentation * add layer build files * add update deps, add gitignore for copied package.json * add test * add instructions to build * dont call instrument for awsinstrumentation test * use done in lambda tests * remove instrument call * fix lambda coverage * add cookie capture * feat: lambda layer support * bump minor (#40) Co-authored-by: prodion23 <[email protected]> * feat: bump minor (#42) Co-authored-by: prodion23 <[email protected]> Co-authored-by: prodion23 <[email protected]> * Release 1.2.0 (#47) * Lambda support (#38) * add support for NODE_OPTIONS require flag * Add lambda instrumentation * add layer build files * add update deps, add gitignore for copied package.json * add test * add instructions to build * dont call instrument for awsinstrumentation test * use done in lambda tests * remove instrument call * fix lambda coverage * add cookie capture * feat: lambda layer support * bump minor (#40) Co-authored-by: prodion23 <[email protected]> * feat: bump minor (#42) Co-authored-by: prodion23 <[email protected]> * Pull release back into main * Support plain http server (#44) * feat: bump minor * Use node builtin methods for header capture, add test for node http server * Revert unneeded body capture change * space * add req body test + read Co-authored-by: prodion23 <[email protected]> * Add hapi support (#46) * Add hapi support * Comment original to not affect cov reports or lint rules * Add compat check * tsc * Wrap values in array * Skip hapi test on non-compat node versions * Fix test * Update framework detection * Fix min version check * Force framework check for hapi * Interpolate url into string to produce original url Co-authored-by: prodion23 <[email protected]> * feat: hapi support Co-authored-by: prodion23 <[email protected]> Co-authored-by: prodion23 <[email protected]> * feat 1.2.0 (#49) Co-authored-by: prodion23 <[email protected]> * fix: update instrumentation to account for plain http server (#51) * fix: update instrumentation to account for plain http server * update tests * re-add hapi compat test check Co-authored-by: prodion23 <[email protected]> * Update plain http server detection, change hapi resp body to capture after route processing (#53) Co-authored-by: prodion23 <[email protected]> Co-authored-by: prodion23 <[email protected]>
1 parent fbc43ee commit fd1e5b2

File tree

8 files changed

+80
-18
lines changed

8 files changed

+80
-18
lines changed

src/HypertraceAgent.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {HttpHypertraceInstrumentation} from "./instrumentation/HttpHypertraceIns
3434
import {patchSails} from "./instrumentation/wrapper/SailsWrapper";
3535
import {Framework} from "./instrumentation/Framework";
3636
import {LambdaRequestHook, LambdaResponseHook} from "./instrumentation/LambdaInstrumentationWrapper";
37+
import {patchHapi} from "./instrumentation/wrapper/HapiWrapper";
3738
const api = require("@opentelemetry/api");
3839

3940
const {Resource} = require('@opentelemetry/resources');
@@ -110,6 +111,7 @@ export class HypertraceAgent {
110111
if(isCompatible("12.0.0")){
111112
// Imports are only allowed at top level
112113
// so instead we need to require it if the node version is modern enough
114+
patchHapi()
113115
const hapiHypertraceInstrumentation = require("./instrumentation/HapiHypertraceInstrumentation")
114116
instrumentations.push(new hapiHypertraceInstrumentation.HapiHypertraceInstrumentation({}),)
115117
}

src/instrumentation/Framework.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ export class Framework {
33
public config: any
44

55
private frameworks: Map<string, boolean>
6-
static supportedFrameworks = ['express', 'koa', 'nestjs', 'sails', 'hapi']
6+
static supportedFrameworks = ['express', 'koa', '@nestjs/core', 'sails', '@hapi/hapi']
77

88
private constructor() {
99
this.frameworks = new Map<string, boolean>()
@@ -24,11 +24,15 @@ export class Framework {
2424
// we can pass filter error up middleware chain cleanly from event based body read
2525
// if it is purely express, we need to end response immediately
2626
public isPureExpress = () => {
27-
return !(this.frameworks['sails'] || this.frameworks['nestjs'] || this.frameworks['koa'] || this.frameworks['hapi']);
27+
return !(this.frameworks['sails'] || this.frameworks['@nestjs/core'] || this.frameworks['koa'] || this.frameworks['@hapi/hapi']);
2828
}
2929

3030
public isExpressBased = () => {
31-
return (this.frameworks['sails'] || this.frameworks['nestjs'])
31+
return (this.frameworks['sails'] || this.frameworks['@nestjs/core'])
32+
}
33+
34+
public anyFrameworks = () => {
35+
return(this.frameworks['sails'] || this.frameworks['@nestjs/core'] || this.frameworks['koa'] || this.frameworks['@hapi/hapi'] || this.frameworks['express'])
3236
}
3337

3438
public noFrameworks = () => {

src/instrumentation/HapiHypertraceInstrumentation.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import {
4545
isPatchableExtMethod,
4646
getRootSpanMetadata,
4747
} from '@opentelemetry/instrumentation-hapi/build/src/utils';
48-
import {captureResponse, captureWithFilter} from "./wrapper/HapiBodyCapture";
48+
import {captureWithFilter} from "./wrapper/HapiBodyCapture";
4949

5050
/** Hapi instrumentation for OpenTelemetry */
5151
export class HapiHypertraceInstrumentation extends InstrumentationBase {
@@ -415,9 +415,7 @@ export class HapiHypertraceInstrumentation extends InstrumentationBase {
415415
attributes: metadata.attributes,
416416
});
417417
try {
418-
let r = await oldHandler(request, h, err);
419-
captureResponse(hapiSpan, h, r)
420-
return r
418+
return await oldHandler(request, h, err);
421419
} catch (err) {
422420
span.recordException(err);
423421
span.setStatus({

src/instrumentation/HttpInstrumentationWrapper.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export class HttpInstrumentationWrapper {
7575
let bodyCapture: BodyCapture = new BodyCapture(<number>Config.getInstance().config.data_capture!.body_max_size_bytes!,
7676
<number>Config.getInstance().config.data_capture!.body_max_processing_size_bytes!)
7777
if (this.shouldCaptureBody(<boolean>Config.getInstance().config.data_capture!.http_body!.request!, headers)) {
78-
if (Framework.getInstance().noFrameworks() || Framework.getInstance().isExpressBased() || Framework.getInstance().isPureExpress()) {
78+
if (!Framework.getInstance().anyFrameworks() || Framework.getInstance().isExpressBased() || Framework.getInstance().isPureExpress()) {
7979
const listener = (chunk: any) => {
8080
bodyCapture.appendData(chunk)
8181
}
@@ -196,7 +196,7 @@ export class HttpInstrumentationWrapper {
196196
}
197197

198198
public static isRecordableContentType(contentType?: string): boolean {
199-
if (contentType === undefined) {
199+
if (contentType === undefined || contentType === null) {
200200
return false
201201
}
202202
for (let recordableType of _RECORDABLE_CONTENT_TYPES) {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import {Framework} from "../Framework";
2+
import {context, trace} from "@opentelemetry/api";
3+
import {HttpInstrumentationWrapper} from "../HttpInstrumentationWrapper";
4+
import {BodyCapture} from "../BodyCapture";
5+
import {Config} from "../../config/config";
6+
7+
let patched = false
8+
const shimmer = require('shimmer');
9+
10+
function HapiWrapWithConfig(config: any): Function {
11+
return function (original: Function) {
12+
const responseBodyEnabled = config.config.data_capture.http_body.response
13+
const maxCaptureSize = config.config.data_capture.body_max_size_bytes
14+
return function () {
15+
let result = arguments[0]
16+
let request = arguments[1]
17+
18+
// Ret is a wrapped hapi response object
19+
let ret = original.apply(this, arguments)
20+
21+
// if our capture fails just return original response
22+
try {
23+
if (responseBodyEnabled) {
24+
let capturedChunk = false
25+
let span = trace.getSpan(context.active())
26+
// @ts-ignore
27+
if (span && !span.hapiAlreadyCaptured) {
28+
// @ts-ignore
29+
let headerContentType = ret._contentType
30+
if (HttpInstrumentationWrapper.isRecordableContentType(headerContentType)) {
31+
// @ts-ignore
32+
span.hapiAlreadyCaptured = true
33+
// @ts-ignore
34+
let bodyCapture = new BodyCapture(Config.getInstance().config.data_capture.body_max_size_bytes,
35+
Config.getInstance().config.data_capture.body_max_processing_size_bytes)
36+
bodyCapture.appendData(result)
37+
// @ts-ignore
38+
span.setAttribute('http.response.body', bodyCapture.dataString())
39+
}
40+
}
41+
}
42+
} catch {
43+
return ret
44+
}
45+
return ret
46+
}
47+
}
48+
}
49+
50+
export function patchHapi() {
51+
if (!Framework.getInstance().available('@hapi/hapi') || patched) {
52+
return
53+
}
54+
patched = true
55+
const hapiResponse = require('@hapi/hapi/lib/response')
56+
57+
shimmer.wrap(hapiResponse, 'wrap', HapiWrapWithConfig(Config.getInstance()))
58+
}

test/instrumentation/HapiTest.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ if(isCompatible("12.0.0") === true){
4949

5050
let expressBased = Framework.getInstance().isExpressBased
5151
let onlyExpress = Framework.getInstance().isPureExpress
52-
let noFrameworks = Framework.getInstance().noFrameworks
52+
let anyFrameworks = Framework.getInstance().anyFrameworks
5353
before(async ()=> {
5454
Framework.getInstance().isExpressBased = () => {return false}
5555
Framework.getInstance().isPureExpress = () => {return false}
56-
Framework.getInstance().noFrameworks = () => {return false}
56+
Framework.getInstance().anyFrameworks = () => {return true}
5757
await server.start();
5858
})
5959

@@ -64,7 +64,7 @@ if(isCompatible("12.0.0") === true){
6464
after( ()=> {
6565
Framework.getInstance().isExpressBased = expressBased
6666
Framework.getInstance().isPureExpress = onlyExpress
67-
Framework.getInstance().isPureExpress = noFrameworks
67+
Framework.getInstance().anyFrameworks = anyFrameworks
6868
server.stop()
6969
agentTestWrapper.stop()
7070
})

test/instrumentation/HttpTest.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ describe('Agent tests', () => {
2828
let server = http.createServer(requestListener)
2929
let originalIncludeExpress = Framework.getInstance().isExpressBased
3030
let originalOnlyExpress = Framework.getInstance().isExpressBased
31-
let originalNoFrameworks = Framework.getInstance().noFrameworks
31+
let originalanyFrameworks = Framework.getInstance().anyFrameworks
3232
before((done)=> {
3333
Framework.getInstance().isExpressBased = () => {return false}
3434
Framework.getInstance().isPureExpress = () => {return false}
35-
Framework.getInstance().noFrameworks = () => {return true}
35+
Framework.getInstance().anyFrameworks = () => {return false}
3636
server.listen(8000)
3737
server.on('listening', () => {done()})
3838
})
@@ -44,7 +44,7 @@ describe('Agent tests', () => {
4444
after( ()=> {
4545
Framework.getInstance().isExpressBased = originalIncludeExpress
4646
Framework.getInstance().isPureExpress = originalOnlyExpress
47-
Framework.getInstance().noFrameworks = originalNoFrameworks
47+
Framework.getInstance().anyFrameworks = originalanyFrameworks
4848
server.close()
4949
agentTestWrapper.stop()
5050
})

test/instrumentation/KoaTest.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ describe('Koa tests', () => {
3232
// otherwise even though we are testing koa, express is still present in the node_modules
3333
let expressBased = Framework.getInstance().isExpressBased
3434
let onlyExpress = Framework.getInstance().isPureExpress
35-
let noFrameworks = Framework.getInstance().noFrameworks
35+
let anyFrameworks = Framework.getInstance().anyFrameworks
3636
before(()=> {
3737
Framework.getInstance().isExpressBased = () => {return false}
3838
Framework.getInstance().isPureExpress = () => {return false}
39-
Framework.getInstance().noFrameworks = () => {return false}
39+
Framework.getInstance().anyFrameworks = () => {return true}
4040
server = app.listen(8000)
4141
})
4242

@@ -47,7 +47,7 @@ describe('Koa tests', () => {
4747
after(()=> {
4848
Framework.getInstance().isExpressBased = expressBased
4949
Framework.getInstance().isPureExpress = onlyExpress
50-
Framework.getInstance().isPureExpress = noFrameworks
50+
Framework.getInstance().anyFrameworks = anyFrameworks
5151
server.close()
5252
})
5353

0 commit comments

Comments
 (0)