Skip to content

Commit

Permalink
Expose logger to action handler (#8)
Browse files Browse the repository at this point in the history
Add the logger instance to the context that is passed in to the action
handler.

This allows the action handler to send logs with the context established
by the action wrapper.

This means that you can do the following in your action handlers:

```ts
const handler: ActionHandler<Context, Input, Output> = (ctx, input) => {
  ctx.logger.info('This is a log from inside the action handler');

  // ...do something and return a result
  return doSomething(input);
};
```

And it will yield this log in addition to the normal logs that the
wrapper emits:

```
[{DisplayName}:{CorrelationId}] Action Started (input: {input})]
[{DisplayName}:{CorrelationId}] This is a log from inside the action handler
[{DisplayName}:{CorrelationId}] Action Completed (data: {data})]
```
  • Loading branch information
tnez committed Jun 29, 2023
1 parent 87ad8ac commit cc3b908
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 5 deletions.
26 changes: 26 additions & 0 deletions .changeset/proud-beds-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
"@tnezdev/actions": minor
---

Add the logger instance to the context that is passed in to the action handler.

This allows the action handler to send logs with the context established by the action wrapper.

This means that you can do the following in your action handlers:

```ts
const handler: ActionHandler<Context, Input, Output> = (ctx, input) => {
ctx.logger.info("This is a log from inside the action handler");

// ...do something and return a result
return doSomething(input);
};
```

And it will yield this log in addition to the normal logs that the wrapper emits:

```
[{DisplayName}:{CorrelationId}] Action Started (input: {input})]
[{DisplayName}:{CorrelationId}] This is a log from inside the action handler
[{DisplayName}:{CorrelationId}] Action Completed (data: {data})]
```
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type GetTemperatureContext = {
scale?: "celsius" | "fahrenheit";
};
export type GetTemperatureInput = { zipcode: string };
export type GetTemperatureOutput = string;
export type GetTemperatureOutput = { temperature: number };

const handler: ActionHandler<
GetTemperatureContext,
Expand All @@ -37,9 +37,10 @@ const handler: ActionHandler<
const { client, scale } = ctx;
const { zipcode } = input;

ctx.logger.info("You can emit logs from inside the action");
const { temperature } = await client.getTempearture(zipcode, { scale });

return temperature;
return { temperature };
};

export const GetTemperatureAction = createAction("GetTemperature", handler);
Expand Down Expand Up @@ -84,5 +85,12 @@ When run, this will produce the following logs:

```txt
[GetTemparature:{correlation-id}] Action Started (input: {"zipcode":"12345"})
[GetTemperature:{correlation-id}] You can emit logs from inside the action
[GetTempearture:{correlation-id}] Action Completed (data: {"temperature":"75˚F"})
```

And the result returned from the action will be:

```
{ ok: true, data: { temperature: 72 } }
```
6 changes: 5 additions & 1 deletion src/action.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ describe("action", () => {

it("should invoke the handler with expected arguments", () => {
const input = "World";
expect(handler).toHaveBeenCalledWith(context, input);
expect(handler).toHaveBeenCalledWith(
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
{ ...context, logger: expect.any(Logger) },
input
);
});

it("should emit expected log when completed", () => {
Expand Down
2 changes: 1 addition & 1 deletion src/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class Action<Context, Input, Output> {

try {
logger.info(`Action Started (input: ${JSON.stringify(input)})`);
const data = await this.handler(this.ctx, input);
const data = await this.handler({ ...this.ctx, logger }, input);
logger.info(`Action Completed (data: ${JSON.stringify(data)})`);
return { ok: true as const, data };
} catch (possibleError) {
Expand Down
4 changes: 3 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { Logger } from "./logger";

export interface ActionBaseContext {
displayName: string;
}
Expand All @@ -13,6 +15,6 @@ export interface ActionResultSad {
}
export type ActionResult<Output> = ActionResultHappy<Output> | ActionResultSad;
export type ActionHandler<Context, Input, Output> = (
ctx: Context & ActionBaseContext,
ctx: Context & ActionBaseContext & { logger: Logger },
input: Input
) => Promise<Output> | Output;

0 comments on commit cc3b908

Please sign in to comment.