Skip to content

Commit

Permalink
add sentry logger tests
Browse files Browse the repository at this point in the history
  • Loading branch information
joshbalfour committed Apr 10, 2024
1 parent 82b6027 commit 4c0ca4c
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 47 deletions.
3 changes: 2 additions & 1 deletion packages/modules/edge-api-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"@reapit-cdk/eslint-config": "workspace:^",
"@reapit-cdk/tsup": "workspace:^",
"@types/aws-lambda": "^8.10.121",
"aws-lambda": "^1.0.7"
"aws-lambda": "^1.0.7",
"jest-fetch-mock": "^3.0.3"
},
"dependencies": {
"@sentry/node": "^7.109.0",
Expand Down
47 changes: 2 additions & 45 deletions packages/modules/edge-api-sdk/src/sentry/sentry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,13 @@ import {
nodeStackLineParser,
exceptionFromError,
dsnFromString,
serializeEnvelope,
} from '@sentry/utils'

import { Envelope, SeverityLevel } from '@sentry/types'
import { SeverityLevel } from '@sentry/types'

import { LogLevel, LogPayload, MinimalLogPayload, Transport } from '../logger'

const encodeUTF8 = (input: string) => new TextEncoder().encode(input)

export function serializeEnvelope(envelope: Envelope): string | Uint8Array {
const [envHeaders, items] = envelope

// Initially we construct our envelope as a string and only convert to binary chunks if we encounter binary data
let parts: string | Uint8Array[] = JSON.stringify(envHeaders)

function append(next: string | Uint8Array): void {
if (typeof parts === 'string') {
parts = typeof next === 'string' ? parts + next : [encodeUTF8(parts), next]
} else {
parts.push(typeof next === 'string' ? encodeUTF8(next) : next)
}
}

for (const item of items) {
const [itemHeaders, payload] = item

append(`\n${JSON.stringify(itemHeaders)}\n`)

if (typeof payload === 'string' || payload instanceof Uint8Array) {
append(payload)
} else {
append(JSON.stringify(payload))
}
}

return typeof parts === 'string' ? parts : concatBuffers(parts)
}

function concatBuffers(buffers: Uint8Array[]): Uint8Array {
const totalLength = buffers.reduce((acc, buf) => acc + buf.length, 0)

const merged = new Uint8Array(totalLength)
let offset = 0
for (const buffer of buffers) {
merged.set(buffer, offset)
offset += buffer.length
}

return merged
}

const stackParser = stackParserFromStackParserOptions(
createStackParser(nodeStackLineParser(createGetModuleFromFilename())),
)
Expand Down
45 changes: 45 additions & 0 deletions packages/modules/edge-api-sdk/src/sentry/serialize-envelope.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Envelope } from '@sentry/types'

const encodeUTF8 = (input: string) => new TextEncoder().encode(input)

export function serializeEnvelope(envelope: Envelope): string | Uint8Array {
const [envHeaders, items] = envelope

// Initially we construct our envelope as a string and only convert to binary chunks if we encounter binary data
let parts: string | Uint8Array[] = JSON.stringify(envHeaders)

function append(next: string | Uint8Array): void {
if (typeof parts === 'string') {
parts = typeof next === 'string' ? parts + next : [encodeUTF8(parts), next]
} else {
parts.push(typeof next === 'string' ? encodeUTF8(next) : next)
}
}

for (const item of items) {
const [itemHeaders, payload] = item

append(`\n${JSON.stringify(itemHeaders)}\n`)

if (typeof payload === 'string' || payload instanceof Uint8Array) {
append(payload)
} else {
append(JSON.stringify(payload))
}
}

return typeof parts === 'string' ? parts : concatBuffers(parts)
}

function concatBuffers(buffers: Uint8Array[]): Uint8Array {
const totalLength = buffers.reduce((acc, buf) => acc + buf.length, 0)

const merged = new Uint8Array(totalLength)
let offset = 0
for (const buffer of buffers) {
merged.set(buffer, offset)
offset += buffer.length
}

return merged
}
2 changes: 1 addition & 1 deletion packages/modules/edge-api-sdk/tests/logger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { CloudFrontRequestEvent } from 'aws-lambda'
import { JSONRequest } from '../src'
import { LogPayload, Logger, LoggerConfig, panic } from '../src/logger'

const generateCloudfrontRequest = ({
export const generateCloudfrontRequest = ({
headers = {
host: [{ key: 'host', value: 'google.com' }],
},
Expand Down
115 changes: 115 additions & 0 deletions packages/modules/edge-api-sdk/tests/sentry.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { enableFetchMocks } from 'jest-fetch-mock'
import fetchMock from 'jest-fetch-mock'
enableFetchMocks()

import { JSONRequest } from '../src'
import { init } from '../src/sentry/sentry'
import { generateCloudfrontRequest } from './logger.test'
import { LogEntry, LogPayload } from '../src/logger'

const generateLogPayload = (entries: LogEntry[]): LogPayload => {
const event = generateCloudfrontRequest({})
const request: JSONRequest<any, any> = {
env: {},
headers: {
host: ['google.com'],
},
method: 'GET',
host: 'google.com',
path: '/',
region: 'eu-west-2',
cookies: [],
body: {},
meta: {
event,
functionName: 'function-name',
functionVersion: 'function-version',
invocationId: 'invocation-id',
sessionId: 'session-id',
},
}

return {
centralize: true,
entries,
event,
functionName: 'functionName',
functionVersion: 'functionVersion',
invocationId: '',
region: '',
request,
timestamp: new Date(0),
sessionId: 'sessionId',
}
}

describe('sentry logger transport', () => {
beforeEach(() => {
fetchMock.resetMocks()
})
it('should init', () => {
init({
dsn: 'https://asdf@qwerty.ingest.sentry.io/123456',
environment: 'environment',
release: 'release',
})
})

it('should send exceptions to sentry', async () => {
const report = init({
dsn: 'https://asdf@qwerty.ingest.sentry.io/123456',
environment: 'environment',
release: 'release',
})

await report(
generateLogPayload([
{
level: 'critical',
message: 'the error message',
timestamp: new Date(0),
error: new Error('oh no'),
},
]),
)

const [endpoint, reqInit] = fetchMock.mock.calls[0]
expect(endpoint).toBe('https://qwerty.ingest.sentry.io/api/123456/envelope/?sentry_key=asdf&sentry_version=7')
expect(reqInit?.method).toBe('post')
const [, eventType, exception] = (reqInit?.body as string)?.split('\n').map((str) => JSON.parse(str)) ?? []
expect(eventType.type).toBe('event')
const values = exception.exception.values
expect(values[0].type).toEqual('Error')
expect(values[0].value).toEqual('oh no')
})

it('should send prior log entries as breadcrumbs', async () => {
const report = init({
dsn: 'https://asdf@qwerty.ingest.sentry.io/123456',
environment: 'environment',
release: 'release',
})

await report(
generateLogPayload([
{
level: 'info',
message: 'something interesting here',
timestamp: new Date(0),
},
{
level: 'critical',
message: 'the error message',
timestamp: new Date(1),
error: new Error('oh no'),
},
]),
)
const [, reqInit] = fetchMock.mock.calls[0]
const [, , exception] = (reqInit?.body as string)?.split('\n').map((str) => JSON.parse(str)) ?? []
expect(exception.breadcrumbs).toEqual([
{ level: 'info', message: 'something interesting here', timestamp: 0 },
{ level: 'fatal', message: 'the error message', timestamp: 1 },
])
})
})
65 changes: 65 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3633,6 +3633,7 @@ __metadata:
"@sentry/utils": "npm:^7.109.0"
"@types/aws-lambda": "npm:^8.10.121"
aws-lambda: "npm:^1.0.7"
jest-fetch-mock: "npm:^3.0.3"
languageName: unknown
linkType: soft

Expand Down Expand Up @@ -6903,6 +6904,15 @@ __metadata:
languageName: node
linkType: hard

"cross-fetch@npm:^3.0.4":
version: 3.1.8
resolution: "cross-fetch@npm:3.1.8"
dependencies:
node-fetch: "npm:^2.6.12"
checksum: ac8c4ca87d2ac0e17a19b6a293a67ee8934881aee5ec9a5a8323c30e9a9a60a0f5291d3c0d633ec2a2f970cbc60978d628804dfaf03add92d7e720b6d37f392c
languageName: node
linkType: hard

"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3":
version: 7.0.3
resolution: "cross-spawn@npm:7.0.3"
Expand Down Expand Up @@ -8573,6 +8583,16 @@ __metadata:
languageName: node
linkType: hard

"jest-fetch-mock@npm:^3.0.3":
version: 3.0.3
resolution: "jest-fetch-mock@npm:3.0.3"
dependencies:
cross-fetch: "npm:^3.0.4"
promise-polyfill: "npm:^8.1.3"
checksum: c119a87fc8b084b94089f44fd83433fc7b8b0f180507b2ffa3b50eb4213a01f9917fab564b303f0d588dee30506942bb0bd611828f368bdd75cb163cf5d967c0
languageName: node
linkType: hard

"jest-get-type@npm:^28.0.2":
version: 28.0.2
resolution: "jest-get-type@npm:28.0.2"
Expand Down Expand Up @@ -9653,6 +9673,20 @@ __metadata:
languageName: node
linkType: hard

"node-fetch@npm:^2.6.12":
version: 2.7.0
resolution: "node-fetch@npm:2.7.0"
dependencies:
whatwg-url: "npm:^5.0.0"
peerDependencies:
encoding: ^0.1.0
peerDependenciesMeta:
encoding:
optional: true
checksum: b24f8a3dc937f388192e59bcf9d0857d7b6940a2496f328381641cb616efccc9866e89ec43f2ec956bbd6c3d3ee05524ce77fe7b29ccd34692b3a16f237d6676
languageName: node
linkType: hard

"node-gyp@npm:latest":
version: 9.4.0
resolution: "node-gyp@npm:9.4.0"
Expand Down Expand Up @@ -10060,6 +10094,13 @@ __metadata:
languageName: node
linkType: hard

"promise-polyfill@npm:^8.1.3":
version: 8.3.0
resolution: "promise-polyfill@npm:8.3.0"
checksum: f735f59e464174f720fec9c41c5029ec1014e62e05d61e39d8d2290a0bc4dd7c36a0782d3202f1775d09d0b33a47fef289db38c437534769b187da22e03bfa23
languageName: node
linkType: hard

"promise-retry@npm:^2.0.1":
version: 2.0.1
resolution: "promise-retry@npm:2.0.1"
Expand Down Expand Up @@ -10900,6 +10941,13 @@ __metadata:
languageName: node
linkType: hard

"tr46@npm:~0.0.3":
version: 0.0.3
resolution: "tr46@npm:0.0.3"
checksum: 8f1f5aa6cb232f9e1bdc86f485f916b7aa38caee8a778b378ffec0b70d9307873f253f5cbadbe2955ece2ac5c83d0dc14a77513166ccd0a0c7fe197e21396695
languageName: node
linkType: hard

"tree-kill@npm:^1.2.2":
version: 1.2.2
resolution: "tree-kill@npm:1.2.2"
Expand Down Expand Up @@ -11357,13 +11405,30 @@ __metadata:
languageName: node
linkType: hard

"webidl-conversions@npm:^3.0.0":
version: 3.0.1
resolution: "webidl-conversions@npm:3.0.1"
checksum: b65b9f8d6854572a84a5c69615152b63371395f0c5dcd6729c45789052296df54314db2bc3e977df41705eacb8bc79c247cee139a63fa695192f95816ed528ad
languageName: node
linkType: hard

"webidl-conversions@npm:^4.0.2":
version: 4.0.2
resolution: "webidl-conversions@npm:4.0.2"
checksum: 594187c36f2d7898f89c0ed3b9248a095fa549ecc1befb10a97bc884b5680dc96677f58df5579334d8e0d1018e5ef075689cfa2a6c459f45a61a9deb512cb59e
languageName: node
linkType: hard

"whatwg-url@npm:^5.0.0":
version: 5.0.0
resolution: "whatwg-url@npm:5.0.0"
dependencies:
tr46: "npm:~0.0.3"
webidl-conversions: "npm:^3.0.0"
checksum: f95adbc1e80820828b45cc671d97da7cd5e4ef9deb426c31bcd5ab00dc7103042291613b3ef3caec0a2335ed09e0d5ed026c940755dbb6d404e2b27f940fdf07
languageName: node
linkType: hard

"whatwg-url@npm:^7.0.0":
version: 7.1.0
resolution: "whatwg-url@npm:7.1.0"
Expand Down

0 comments on commit 4c0ca4c

Please sign in to comment.