Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ca177fa
Add safe failure to execution time calculation
timoruppell Nov 10, 2023
255de1c
Fix flow and add observation of non-async wrappees
timoruppell Nov 10, 2023
157acb8
Fix formatting and linter errors
timoruppell Nov 10, 2023
252cace
Bump version
timoruppell Nov 10, 2023
b329aeb
Convert indentation
timoruppell Nov 10, 2023
610c4b5
Remove superfluous checks
timoruppell Nov 10, 2023
f54abad
Fix linter errors
timoruppell Nov 10, 2023
afe703a
Add metadata
timoruppell Nov 10, 2023
4a173b4
Fix TS errors
timoruppell Nov 10, 2023
a3ed551
Update package.json
timoruppell Nov 10, 2023
964e8e8
Add new build
timoruppell Nov 10, 2023
a80ff50
Update README
timoruppell Nov 10, 2023
d4938a6
Update LICENSE
timoruppell Nov 10, 2023
65afc63
Merge branch 'main' into fix-async-bug
timoruppell Nov 10, 2023
c466f06
Update sourcemap
timoruppell Nov 10, 2023
feda74d
Remove additional context
timoruppell Nov 10, 2023
47e48dd
Improve test for async function
timoruppell Nov 10, 2023
087360f
Rebuild
timoruppell Nov 10, 2023
dd6e9b0
Add observations to logs
timoruppell Nov 10, 2023
fa57a46
Expand test coverage
timoruppell Nov 15, 2023
28445ec
Fix test to account for very fast execution
timoruppell Nov 15, 2023
f7ca66c
Add more test coverage
timoruppell Nov 15, 2023
37ba3bc
Fix timer
timoruppell Nov 15, 2023
a7a31d8
Merge branch 'fix-async-bug' into feature-add-obervations
timoruppell Nov 15, 2023
60bf963
Update tests
timoruppell Nov 15, 2023
9a86cef
Fix variable casing
timoruppell Nov 15, 2023
53f444f
Clean up tests
timoruppell Nov 15, 2023
f5bbd76
Separate checks for aync and Promise
timoruppell Nov 24, 2023
52bfab4
Rebuild
timoruppell Nov 24, 2023
9a74b92
Update tests
timoruppell Nov 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
837 changes: 163 additions & 674 deletions LICENSE

Large diffs are not rendered by default.

21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
# Firetail Javascript Lambda Middleware

# FireTail Javascript Lambda Middleware

### Overview

The purpose of this module is to correctly log out the AWS Lambda event and response payload to allow the firetail extension to then send it on to the firetail logging api
The purpose of this module is to correctly log out the AWS Lambda event and response payload to allow the FireTail extension to then send it on to the FireTail logging API.

[![Code Coverage](https://github.com/FireTail-io/firetail-js-lambda/actions/workflows/codecov.yml/badge.svg)](https://github.com/FireTail-io/firetail-js-lib/actions/workflows/codecov.yml) [![codecov](https://codecov.io/gh/FireTail-io/firetail-js-lambda/branch/main/graph/badge.svg?token=BN44NPKV8H)](https://codecov.io/gh/FireTail-io/firetail-js-lambda) [![License](https://img.shields.io/pypi/l/firetail.svg)](https://github.com/FireTail-io/firetail-js-lambda/blob/main/LICENSE.txt)
[![Code Coverage](https://github.com/FireTail-io/firetail-js-lambda/actions/workflows/codecov.yml/badge.svg)](https://github.com/FireTail-io/firetail-js-lib/actions/workflows/codecov.yml) [![codecov](https://codecov.io/gh/FireTail-io/firetail-js-lambda/branch/main/graph/badge.svg?token=BN44NPKV8H)](https://codecov.io/gh/FireTail-io/firetail-js-lambda)[![License: LGPL v3](https://img.shields.io/badge/License-LGPL_v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0)

The [![npm version](https://badge.fury.io/js/@public.firetail.io%2Ffiretail-js-lambda.svg)](https://www.npmjs.com/package/@public.firetail.io/firetail-js-lambda) is a function that wraps around an event handler function in a AWS Lambda to extract the event and response payloads into a base64 logging message.

### Installation
Install the module into your project

Implementing Middleware in lambda function
Install the module into your project.

Implementing Middleware in lambda function:

```js
import * as firetailWrapper from '@public.firetail.io/firetail-js-lambda'
import * as firetailWrapper from "@public.firetail.io/firetail-js-lambda";

module.exports.myFn = firetailWrapper((event,context) => {
module.exports.myFn = firetailWrapper((event, context) => {
// do work here..
return {
statusCode:200,
body: JSON.stringify(data)
statusCode: 200,
body: JSON.stringify(data),
};
});
```
257 changes: 208 additions & 49 deletions __tests__/index.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,218 @@
const Serverless_Events = require('./sampleEvents.json')
const data = require('./animals.json')
const Serverless_Events = require("./sampleEvents.json");
const data = require("./animals.json");
const firetailWrapper = require("../dist");

const timer = t => new Promise(r => setTimeout(() => r(), t));

//=====================================================
//====================================== test GET calls
//=====================================================

describe('test Firetail:Serverless', () => {
describe("test Firetail:Serverless", () => {
test("should work when wrapping a Promise", done => {
const time = 200;
const next = firetailWrapper(
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
statusCode: 200,
body: JSON.stringify(data),
});
}, time);
}),
);

const cLog = console.log;

console.log = txt => {
expect(txt.startsWith("firetail:log-ext:")).toBe(true);
const base64 = txt?.slice(17);
const json = JSON.parse(atob(base64));
expect(json.execution_time).toBeGreaterThan(time - 10);
};
next(Serverless_Events["lambda function url"]).then(
({ statusCode, body }) => {
expect(statusCode).toBe(200);
expect(body).toBe(
'[{"id":1,"name":"Bubbles","tag":"fish"},' +
'{"id":2,"name":"Jax","tag":"cat"},' +
'{"id":3,"name":"Tiger Lily","tag":"cat"},' +
'{"id":4,"name":"Buzz","tag":"dog"},' +
'{"id":5,"name":"Duke","owner":"Tom"}]',
);
console.log = cLog.bind(console);
done();
},
);
});

test("should work when wrapping an async function", done => {
const time = 300;
const next = firetailWrapper(async event => {
await timer(time);
const statusCode = 200;
if (
event.queryStringParameters &&
event.queryStringParameters.limit
) {
return {
statusCode,
body: JSON.stringify(
data.slice(0, event.queryStringParameters.limit),
),
};
}
return {
statusCode,
body: JSON.stringify(data),
};
});

const cLog = console.log;

test('should work with lambda function url', done => {
console.log = txt => {
expect(txt.startsWith("firetail:log-ext:")).toBe(true);
const base64 = txt?.slice(17);
const json = JSON.parse(atob(base64));
expect(json.execution_time).toBeGreaterThan(time - 10);
};
next(Serverless_Events["lambda function url"])
.then(({ statusCode, body }) => {
expect(statusCode).toBe(200);
expect(body).toBe(
'[{"id":1,"name":"Bubbles","tag":"fish"},' +
'{"id":2,"name":"Jax","tag":"cat"},' +
'{"id":3,"name":"Tiger Lily","tag":"cat"},' +
'{"id":4,"name":"Buzz","tag":"dog"},' +
'{"id":5,"name":"Duke","owner":"Tom"}]',
);
return next(Serverless_Events["api Gateway Proxy Event"]);
})
.then(({ statusCode, body }) => {
expect(statusCode).toBe(200);
expect(body).toBe(
'[{"id":1,"name":"Bubbles","tag":"fish"},' +
'{"id":2,"name":"Jax","tag":"cat"}]',
);
console.log = cLog.bind(console);
done();
});
});

test("should work when wrapping a sync function", done => {
const next = firetailWrapper(event => {
const statusCode = 200;
if (
event.queryStringParameters &&
event.queryStringParameters.limit
) {
return {
statusCode,
body: JSON.stringify(
data.slice(0, event.queryStringParameters.limit),
),
};
}
return {
statusCode,
body: JSON.stringify(data),
};
});

const cLog = console.log;

console.log = txt => {
expect(txt.startsWith("firetail:log-ext:")).toBe(true);
const base64 = txt?.slice(17);
const json = JSON.parse(atob(base64));
expect(json.execution_time).toBeLessThan(10);
};
next(Serverless_Events["lambda function url"])
.then(({ statusCode, body }) => {
expect(statusCode).toBe(200);
expect(body).toBe(
'[{"id":1,"name":"Bubbles","tag":"fish"},' +
'{"id":2,"name":"Jax","tag":"cat"},' +
'{"id":3,"name":"Tiger Lily","tag":"cat"},' +
'{"id":4,"name":"Buzz","tag":"dog"},' +
'{"id":5,"name":"Duke","owner":"Tom"}]',
);
return next(Serverless_Events["api Gateway Proxy Event"]);
})
.then(({ statusCode, body }) => {
expect(statusCode).toBe(200);
expect(body).toBe(
'[{"id":1,"name":"Bubbles","tag":"fish"},' +
'{"id":2,"name":"Jax","tag":"cat"}]',
);
console.log = cLog.bind(console);
done();
});
});

const next = firetailWrapper((event) => {
const statusCode = 200
if(event.queryStringParameters
&& event.queryStringParameters.limit){
return {
statusCode,
body: JSON.stringify(data.slice(0, event.queryStringParameters.limit)),
};
test("should not throw when wrapping a non-function", done => {
const next = firetailWrapper({
statusCode: 200,
body: "some body",
});

const cLog = console.log;

console.log = txt => {
expect(txt.startsWith("firetail:log-ext:")).toBe(true);
const base64 = txt?.slice(17);
const json = JSON.parse(atob(base64));
expect(json.execution_time).toBeLessThan(10);
};
next(Serverless_Events["lambda function url"]).then(
({ statusCode, body }) => {
expect(statusCode).toBe(200);
expect(body).toBe("some body");
done();
},
);
});

test("should not throw when Date() does not work or status code is not found", done => {
const next = firetailWrapper({
statusCode: null,
body: "some body",
});

const d = Date;

class C {
constructor(x, y) {
this.x = x;
this.y = y;
}
foo() {
return this.x + this.y;
}
}
return {
statusCode,
body: JSON.stringify(data),

Date = class D {
constructor() {}
getTime() {
return "not a date";
}
};

const cLog = console.log;

console.log = txt => {
expect(txt.startsWith("firetail:log-ext:")).toBe(true);
const base64 = txt?.slice(17);
const json = JSON.parse(atob(base64));
expect(json.execution_time).toBe(0);
expect(json.response.statusCode).toBe(200);
};
});

const cLog = console.log

console.log = (txt)=>{
expect(txt.startsWith("firetail:log-ext:")).toBe(true);
const payload = JSON.parse(Buffer.from(txt.slice(17), "base64").toString("ascii"));
expect(payload).toHaveProperty('execution_time');
expect(payload).toHaveProperty('event');
expect(payload).toHaveProperty('response');
expect(payload.response).toHaveProperty('statusCode');
expect(payload.response).toHaveProperty('body');
}

next(Serverless_Events["lambda function url"])
.then((a)=>{
const {statusCode,body} = a
expect(statusCode).toBe(200);
expect(body).toBe('[{"id":1,"name":"Bubbles","tag":"fish"},'+
'{"id":2,"name":"Jax","tag":"cat"},'+
'{"id":3,"name":"Tiger Lily","tag":"cat"},'+
'{"id":4,"name":"Buzz","tag":"dog"},'+
'{"id":5,"name":"Duke","owner":"Tom"}]')
return next(Serverless_Events["api Gateway Proxy Event"])
}).then(({statusCode,body})=>{
expect(statusCode).toBe(200);
expect(body).toBe('[{"id":1,"name":"Bubbles","tag":"fish"},'+
'{"id":2,"name":"Jax","tag":"cat"}]')
console.log = cLog.bind(console)
done()
})

})
})
next(Serverless_Events["lambda function url"]).then(
({ statusCode, body }) => {
expect(statusCode).toBe(null);
expect(body).toBe("some body");
done();
},
);
});
});
6 changes: 4 additions & 2 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { APIGatewayProxyEvent, APIGatewayProxyEventV2, Context } from 'aws-lambda';
declare function wrap(next: Function): (event: APIGatewayProxyEvent | APIGatewayProxyEventV2, context: Context) => any;
import { APIGatewayProxyEvent, APIGatewayProxyEventV2, Context } from "aws-lambda";
declare function wrap(next: Promise | (Function & {
then?: Function;
})): (event: APIGatewayProxyEvent | APIGatewayProxyEventV2, context: Context) => any;
export = wrap;
55 changes: 43 additions & 12 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading