Skip to content

Commit

Permalink
logger refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
justinmchase committed Nov 14, 2024
1 parent d8a6281 commit 1b3c1a5
Show file tree
Hide file tree
Showing 19 changed files with 133 additions and 225 deletions.
10 changes: 9 additions & 1 deletion deno.jsonc
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
{
"name": "@justinmchase/grove",
"version": "0.5.4",
"exports": "./mod.ts",
"exports": {
".": "./mod.ts",
"./controllers": "./src/controllers/mod.ts",
"./errors": "./src/errors/mod.ts",
"./logging": "./src/logging/mod.ts",
"./modes": "./src/modes/mod.ts",
"./services": "./src/services/mod.ts",
"./util": "./src/util/mod.ts"
},
"tasks": {
"check": "deno fmt && deno lint && deno test && npx jsr publish --dry-run --allow-dirty",
"example": "deno run -A example/main.ts",
Expand Down
4 changes: 2 additions & 2 deletions src/context.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { State } from "@oak/oak";
import type { ILogger } from "./logging/mod.ts";
import type { Logger } from "./logging/mod.ts";

export interface IContext {
log: ILogger;
log: Logger;
}

export interface IState<
Expand Down
1 change: 0 additions & 1 deletion src/controllers/error.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export class ErrorController<
ctx.response.body = { ok: false, message };
ctx.response.headers.set("Content-Type", "application/json");
ctx.state.context.log.error(
"server_error",
`An unhandled error occurred: ${message}`,
err,
{
Expand Down
25 changes: 10 additions & 15 deletions src/controllers/github.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
import type { GitHubService } from "../services/github.service.ts";
import type { IContext, IState } from "../context.ts";
import type { Controller } from "./controller.ts";
import type { ILogger } from "../logging/mod.ts";
import type { Logger } from "../logging/mod.ts";

export interface IGitHubWebhookConfig {
githubWebhookPath: string;
Expand Down Expand Up @@ -44,7 +44,7 @@ export abstract class GithubWebhookController<
await undefined;
}

private async handler(log: ILogger, req: Request, res: Response) {
private async handler(log: Logger, req: Request, res: Response) {
const githubEvent = req.headers.get("X-GitHub-Event") as
| GitHubEventName
| "ping"
Expand All @@ -55,8 +55,7 @@ export abstract class GithubWebhookController<
| GitHubDeploymentProtectionRuleEvent;
const { action, sender, repository } = event;
log.info(
"github_webhook",
`github event ${githubEvent}`,
`github webhook event ${githubEvent}`,
{
githubEvent,
action,
Expand Down Expand Up @@ -87,15 +86,13 @@ export abstract class GithubWebhookController<
}

protected async unsupportedEvent(
log: ILogger,
log: Logger,
githubEvent: string | null,
res: Response,
// deno-lint-ignore no-explicit-any
body: any,
body: unknown,
) {
log.warn(
"github_unsupported_event",
`The event ${githubEvent} was recieved but is not supported`,
`The github webhook event ${githubEvent} was recieved but is not supported`,
{ body },
);
res.status = Status.OK;
Expand All @@ -106,11 +103,11 @@ export abstract class GithubWebhookController<
}

protected async handlePingEvent(
log: ILogger,
log: Logger,
res: Response,
event: GitHubPingEvent,
) {
log.debug("github_event_ping", `The ping event was received`, { event });
log.debug(`A ping event was received`, { event });
res.status = Status.OK;
res.body = {
ok: true,
Expand All @@ -119,14 +116,13 @@ export abstract class GithubWebhookController<
}

protected async handleInstallationEvent(
log: ILogger,
log: Logger,
res: Response,
event: GitHubInstallationEvent,
) {
const { action, installation: { id, app_slug, account: { login } } } =
event;
log.debug(
"github_event_installation",
`${app_slug} installation ${id} ${action} for ${login}`,
{
action,
Expand All @@ -143,7 +139,7 @@ export abstract class GithubWebhookController<
}

protected async handleDeploymentProtectionRuleEvent(
log: ILogger,
log: Logger,
res: Response,
event: GitHubDeploymentProtectionRuleEvent,
) {
Expand All @@ -157,7 +153,6 @@ export abstract class GithubWebhookController<
sender: { id: senderId, login },
} = event;
log.debug(
"github_event_deployment_protection_rule",
`deployment protection rule ${action} for ${deploymentId}:${full_name}/${environment} by ${senderId}:${login}`,
{
action,
Expand Down
1 change: 0 additions & 1 deletion src/controllers/log.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export class LogController<
const ms = `${t}ms`;
const { response: { status } } = ctx;
ctx.state.context.log.info(
"request",
`${status} ${method} ${url.pathname} ${ms}`,
{
status,
Expand Down
19 changes: 5 additions & 14 deletions src/grove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ export class Grove<TContext extends IContext> {
// todo: use after https://github.com/c4spar/deno-cliffy/issues/655 is resolved
const defaultMode = this.config.modes[0].name;
context.log.info(
"grove_default_mode",
`no mode specified, using default mode ${defaultMode}`,
{ mode: defaultMode, args },
);
Expand All @@ -133,25 +132,17 @@ export class Grove<TContext extends IContext> {

private async run(args: unknown, context: TContext, mode: IMode<TContext>) {
const { name } = mode;
context.log.info("grove_run", `grove running mode ${name}`, {
context.log.info(`grove running mode ${name}`, {
mode: name,
args,
});
try {
await mode.run(args, context);
} catch (err) {
if (err instanceof Error) {
context.log.error("grove_runtime_error", err.message, err, {
mode: mode.name,
args,
});
} else {
context.log.error("grove_runtime_error", "Unknown error", new Error(), {
mode: mode.name,
args,
err,
});
}
context.log.error("grove error", err, {
mode: mode.name,
args,
});
}
}
}
15 changes: 7 additions & 8 deletions src/logging/aggregate.logger.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { Logger } from "./logger.ts";
import { BaseLogger } from "./base.logger.ts";
import type { LogLevel } from "./logLevel.ts";
import type { ILogger } from "./logger.interface.ts";
import type { Logger } from "./logger.interface.ts";

export class AggregateLogger extends Logger {
private readonly loggers: ILogger[];
constructor(...loggers: ILogger[]) {
export class AggregateLogger extends BaseLogger {
private readonly loggers: Logger[];
constructor(...loggers: Logger[]) {
super();
this.loggers = [...loggers];
}
public async log(
level: LogLevel,
name: string,
message: string,
data: Record<string, unknown>,
data: Record<keyof unknown, unknown>,
) {
await Promise.all(
this.loggers.map((logger) => logger.log(level, name, message, data)),
this.loggers.map((logger) => logger.log(level, message, data)),
);
}
}
12 changes: 4 additions & 8 deletions src/logging/azure.logger.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { snakeCase } from "@wok/case";
import { encodeBase64 } from "@std/encoding/base64";
import { toSerializable } from "@justinmchase/serializable";
import { Status } from "@oak/oak";
import { Logger } from "./logger.ts";
import { BaseLogger } from "./base.logger.ts";
import { UnexpectedStatusError } from "../errors/mod.ts";
import { readOptionalString, readRequiredString } from "../util/config.ts";
import { hmacCreateKey, hmacSign } from "../util/hmac.ts";
import type { LogLevel } from "./logLevel.ts";

export class AzureLogger extends Logger {
export class AzureLogger extends BaseLogger {
constructor(
private readonly workspaceId: string,
private readonly cryptoKey: CryptoKey,
Expand All @@ -30,17 +29,14 @@ export class AzureLogger extends Logger {

public async log(
level: LogLevel,
name: string,
message: string,
data: Record<string, unknown>,
data: Record<keyof unknown, unknown>,
) {
const n = snakeCase(name);
const m = JSON.stringify(message.replace(/"/g, "'"));
const d = JSON.stringify(toSerializable(data));
const line = `${level} ${n} ${m} ${d}`;
const line = `${level} ${m} ${d}`;
const json = JSON.stringify([{
level,
name: n,
message: m,
data: d,
line,
Expand Down
56 changes: 56 additions & 0 deletions src/logging/base.logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { LogLevel } from "./logLevel.ts";
import type { Logger } from "./logger.interface.ts";

export abstract class BaseLogger implements Logger {
public abstract log(
level: LogLevel,
message: string,
data: Record<keyof unknown, unknown>,
): Promise<void>;

public async trace(
message: string,
data: Record<keyof unknown, unknown> = {},
) {
await this.log(LogLevel.Trace, message, data);
}

public async debug(
message: string,
data: Record<keyof unknown, unknown> = {},
) {
await this.log(LogLevel.Debug, message, data);
}

public async warn(
message: string,
data: Record<keyof unknown, unknown> = {},
) {
await this.log(LogLevel.Warn, message, data);
}

public async info(
message: string,
data: Record<keyof unknown, unknown> = {},
) {
await this.log(LogLevel.Info, message, data);
}

public async error(
message: string,
error: unknown,
data: Record<keyof unknown, unknown> = {},
) {
await this.log(LogLevel.Error, message, {
...data,
error,
});
}

public async critical(
message: string,
data: Record<keyof unknown, unknown> = {},
) {
await this.log(LogLevel.Critical, message, data);
}
}
11 changes: 4 additions & 7 deletions src/logging/console.logger.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { snakeCase } from "@wok/case";
import {
bgBlue,
bgRed,
Expand All @@ -10,21 +9,19 @@ import {
} from "@std/fmt/colors";
import { toSerializable } from "@justinmchase/serializable";
import { LogLevel } from "./logLevel.ts";
import { Logger } from "./logger.ts";
import { BaseLogger } from "./base.logger.ts";

export class ConsoleLogger extends Logger {
export class ConsoleLogger extends BaseLogger {
private readonly isTTY: boolean;
constructor() {
super();
this.isTTY = Deno.stdout.isTerminal();
}
public async log(
level: LogLevel,
name: string,
message: string,
data: Record<string, unknown>,
data: Record<keyof unknown, unknown>,
) {
const n = snakeCase(name);
const m = JSON.stringify((message ?? "").replace(/"/g, "'"));
const d = JSON.stringify(toSerializable(data));
const l = (() => {
Expand All @@ -47,6 +44,6 @@ export class ConsoleLogger extends Logger {
return level;
}
})();
await console.log(`${l} ${n} ${m} ${d}`);
await console.log(`${l} ${m} ${d}`);
}
}
27 changes: 10 additions & 17 deletions src/logging/logger.interface.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,34 @@
import type { LogLevel } from "./logLevel.ts";

export interface ILogger {
export type Logger = {
log(
level: LogLevel,
name: string,
message: string,
data?: Record<string, unknown>,
data?: Record<keyof unknown, unknown>,
): Promise<void>;
trace(
name: string,
message: string,
data?: Record<string, unknown>,
data?: Record<keyof unknown, unknown>,
): Promise<void>;
debug(
name: string,
message: string,
data?: Record<string, unknown>,
data?: Record<keyof unknown, unknown>,
): Promise<void>;
warn(
name: string,
message: string,
data?: Record<string, unknown>,
data?: Record<keyof unknown, unknown>,
): Promise<void>;
info(
name: string,
message: string,
data?: Record<string, unknown>,
data?: Record<keyof unknown, unknown>,
): Promise<void>;
error(
name: string,
message: string,
error: Error,
data?: Record<string, unknown>,
error: unknown,
data?: Record<keyof unknown, unknown>,
): Promise<void>;
critical(
name: string,
message: string,
data?: Record<string, unknown>,
data?: Record<keyof unknown, unknown>,
): Promise<void>;
}
};
Loading

0 comments on commit 1b3c1a5

Please sign in to comment.