diff options
| author | Yuqian Yang <crupest@crupest.life> | 2025-06-11 15:26:43 +0800 | 
|---|---|---|
| committer | Yuqian Yang <crupest@crupest.life> | 2025-06-11 15:26:43 +0800 | 
| commit | 8eb35af237d400ea17e1f2d3b1609928ea98344e (patch) | |
| tree | 62c3a9f77d65fe49a8dd2c0d3e94890fdbb30089 /deno | |
| parent | e759291d4a1e6a162265c737608c26aea43537d0 (diff) | |
| download | crupest-8eb35af237d400ea17e1f2d3b1609928ea98344e.tar.gz crupest-8eb35af237d400ea17e1f2d3b1609928ea98344e.tar.bz2 crupest-8eb35af237d400ea17e1f2d3b1609928ea98344e.zip | |
fix(mail-server): log output bug.
Diffstat (limited to 'deno')
| -rw-r--r-- | deno/base/log.ts | 97 | ||||
| -rw-r--r-- | deno/mail-relay/app.ts | 11 | ||||
| -rw-r--r-- | deno/mail-relay/dumb-smtp-server.ts | 40 | ||||
| -rw-r--r-- | deno/mail-relay/mail.ts | 14 | 
4 files changed, 63 insertions, 99 deletions
| diff --git a/deno/base/log.ts b/deno/base/log.ts index d0a5b80..cc71dfa 100644 --- a/deno/base/log.ts +++ b/deno/base/log.ts @@ -4,43 +4,19 @@ import { toFileNameString } from "./date.ts";  export type LogLevel = "error" | "warn" | "info"; -export interface LogEntry { -  content: [unknown, ...unknown[]]; +export interface LogOptions {    level?: LogLevel;    cause?: unknown;  } -export interface LogEntryBuilder { -  withLevel(level: LogLevel): LogEntryBuilder; -  withCause(cause: unknown): LogEntryBuilder; -  setError(error: boolean): LogEntryBuilder; -  write(): void; -} -  export interface ExternalLogStream extends Disposable {    stream: WritableStream;  }  export class Logger { -  #indentSize = 2; +  #defaultLevel = "info" as const;    #externalLogDir?: string; -  #contextStack: { depth: number; level: LogLevel }[] = [ -    { depth: 0, level: "info" }, -  ]; - -  get #context() { -    return this.#contextStack.at(-1)!; -  } - -  get indentSize() { -    return this.#indentSize; -  } - -  set indentSize(value: number) { -    this.#indentSize = value; -  } -    get externalLogDir() {      return this.#externalLogDir;    } @@ -54,64 +30,37 @@ export class Logger {      }    } -  write(entry: LogEntry): void { -    const { content, level, cause } = entry; -    const [message, ...rest] = content; -    console[level ?? this.#context.level]( -      " ".repeat(this.#indentSize * this.#context.depth) + String(message), -      ...(cause != null ? [cause, ...rest] : rest), -    ); +  write(message: string, options?: LogOptions): void { +    const logFunction = console[options?.level ?? this.#defaultLevel]; +    if (options?.cause != null) { +      logFunction.call(console, message, options.cause); +    } else { +      logFunction.call(console, message); +    }    } -  push(entry: LogEntry): Disposable { -    this.write(entry); -    this.#contextStack.push({ -      depth: this.#context.depth + 1, -      level: entry.level ?? this.#context.level, -    }); -    return { -      [Symbol.dispose]: () => { -        this.#contextStack.pop(); -      }, -    }; +  info(message: string) { +    this.write(message, { level: "info" });    } -  info(message: unknown, ...args: unknown[]) { -    this.write({ level: "info", content: [message, ...args] }); +  tagInfo(tag: string, message: string) { +    this.info(tag + " " + message);    } -  warn(message: unknown, ...args: unknown[]) { -    this.write({ level: "warn", content: [message, ...args] }); +  warn(message: string) { +    this.write(message, { level: "warn" });    } -  error(message: unknown, ...args: unknown[]) { -    this.write({ level: "error", content: [message, ...args] }); +  tagWarn(tag: string, message: string) { +    this.warn(tag + " " + message);    } -  builder(message: unknown, ...args: unknown[]): LogEntryBuilder { -    const entry: LogEntry = { -      content: [message, ...args], -      level: "info", -      cause: undefined, -    }; -    const builder: LogEntryBuilder = { -      withCause: (cause) => { -        entry.cause = cause; -        return builder; -      }, -      withLevel: (level) => { -        entry.level = level; -        return builder; -      }, -      setError: (error) => { -        if (error) entry.level = "error"; -        return builder; -      }, -      write: () => { -        this.write(entry); -      }, -    }; -    return builder; +  error(message: string, cause?: unknown) { +    this.write(message, { level: "info", cause }); +  } + +  tagError(tag: string, message: string, cause?: unknown) { +    this.error(tag + " " + message, cause);    }    async createExternalLogStream( diff --git a/deno/mail-relay/app.ts b/deno/mail-relay/app.ts index 3cac44b..d96fa1d 100644 --- a/deno/mail-relay/app.ts +++ b/deno/mail-relay/app.ts @@ -43,7 +43,7 @@ export function createHono(    const hono = new Hono();    hono.onError((err, c) => { -    logger.error(err); +    logger.error("Hono handler throws an error.", err);      return c.json({ msg: "Server error, check its log." }, 500);    });    hono.use(honoLogger()); @@ -81,10 +81,9 @@ export async function sendMail(logger: Logger, port: number) {      method: "post",      body: text,    }); -  logger.builder(res).setError(!res.ok).write(); -  logger -    .builder("Body\n" + (await res.text())) -    .setError(!res.ok) -    .write(); +  logger.write(Deno.inspect(res), { level: res.ok ? "info" : "error" }); +  logger.write(Deno.inspect(await res.text()), { +    level: res.ok ? "info" : "error", +  });    if (!res.ok) Deno.exit(-1);  } diff --git a/deno/mail-relay/dumb-smtp-server.ts b/deno/mail-relay/dumb-smtp-server.ts index 15cafa5..1a1090a 100644 --- a/deno/mail-relay/dumb-smtp-server.ts +++ b/deno/mail-relay/dumb-smtp-server.ts @@ -17,6 +17,8 @@ function createResponses(host: string, port: number | string) {    } as const;  } +const LOG_TAG = "[dumb-smtp]"; +  export class DumbSmtpServer {    #logger;    #deliverer; @@ -33,9 +35,12 @@ export class DumbSmtpServer {    async #handleConnection(conn: Deno.Conn) {      using disposeStack = new DisposableStack();      disposeStack.defer(() => { -      this.#logger.info("Close smtp session tcp connection."); +      this.#logger.tagInfo(LOG_TAG, "Close session's tcp connection.");        conn.close();      }); + +    this.#logger.tagInfo(LOG_TAG, "New session's tcp connection established."); +      const writer = conn.writable.getWriter();      disposeStack.defer(() => writer.releaseLock());      const reader = conn.readable.getReader(); @@ -43,8 +48,10 @@ export class DumbSmtpServer {      const [decoder, encoder] = [new TextDecoder(), new TextEncoder()];      const decode = (data: Uint8Array) => decoder.decode(data); -    const send = async (s: string) => +    const send = async (s: string) => { +      this.#logger.tagInfo(LOG_TAG, "Send line: " + s);        await writer.write(encoder.encode(s + CRLF)); +    };      let buffer: string = "";      let rawMail: string | null = null; @@ -65,7 +72,7 @@ export class DumbSmtpServer {          buffer = buffer.slice(eolPos + CRLF.length);          if (rawMail == null) { -          this.#logger.info("Smtp server received line:", line); +          this.#logger.tagInfo(LOG_TAG, "Received line: " + line);            const upperLine = line.toUpperCase();            if (upperLine.startsWith("EHLO") || upperLine.startsWith("HELO")) {              await send(this.#responses["EHLO"]); @@ -75,26 +82,32 @@ export class DumbSmtpServer {              await send(this.#responses["RCPT"]);            } else if (upperLine === "DATA") {              await send(this.#responses["DATA"]); -            this.#logger.info("Begin to receive mail data..."); +            this.#logger.tagInfo(LOG_TAG, "Begin to receive mail data...");              rawMail = "";            } else if (upperLine === "QUIT") {              await send(this.#responses["QUIT"]);              return;            } else { -            this.#logger.warn("Smtp server command unrecognized:", line); +            this.#logger.tagWarn( +              LOG_TAG, +              "Unrecognized command from client: " + line, +            );              await send(this.#responses["INVALID"]);              return;            }          } else {            if (line === ".") {              try { -              this.#logger.info("Done receiving mail data, begin to relay..."); +              this.#logger.tagInfo( +                LOG_TAG, +                "Mail data Received, begin to relay...", +              );                const { message } = await this.#deliverer.deliverRaw(rawMail);                await send(`250 2.6.0 ${message}`);                rawMail = null; -              this.#logger.info("Done SMTP mail session."); +              this.#logger.tagInfo(LOG_TAG, "Relay succeeded.");              } catch (err) { -              this.#logger.info(err); +              this.#logger.tagError(LOG_TAG, "Relay failed.", err);                await send("554 5.3.0 Error: check server log");                return;              } @@ -110,16 +123,19 @@ export class DumbSmtpServer {    async serve(options: { hostname: string; port: number }) {      const listener = Deno.listen(options);      this.#responses = createResponses(options.hostname, options.port); -    this.#logger.info( -      `Dumb SMTP server starts running on ${this.#responses.serverName}.`, +    this.#logger.tagInfo( +      LOG_TAG, +      `Dumb SMTP server starts to listen on ${this.#responses.serverName}.`,      );      for await (const conn of listener) {        try {          await this.#handleConnection(conn);        } catch (cause) { -        this.#logger.error( -          "One smtp connection session throws an error " + cause, +        this.#logger.tagError( +          LOG_TAG, +          "Tcp connection throws an error.", +          cause,          );        }      } diff --git a/deno/mail-relay/mail.ts b/deno/mail-relay/mail.ts index 8c977fe..12d5972 100644 --- a/deno/mail-relay/mail.ts +++ b/deno/mail-relay/mail.ts @@ -31,7 +31,9 @@ class MailSimpleParsedHeaders {      if (match != null) {        return match[1];      } else { -      this.#logger?.warn("Invalid message-id header of mail: ", messageIdField); +      this.#logger?.warn( +        "Invalid message-id header of mail: " + messageIdField, +      );        return undefined;      }    } @@ -240,8 +242,7 @@ export abstract class MailDeliverer {        await hook.callback(context);      } -    context.logger.info("Deliver result:"); -    context.logger.info(context.result); +    context.logger.info("Deliver result:\n" + Deno.inspect(context.result));      if (context.result.hasError()) {        throw new Error("Mail failed to deliver."); @@ -290,8 +291,8 @@ export class RecipientFromHeadersHook implements MailDeliverHook {          .forEach((r) => context.recipients.add(r));        context.logger.info( -        "Recipients found from mail headers: ", -        [...context.recipients].join(" "), +        "Recipients found from mail headers: " + +          [...context.recipients].join(", "),        );      }      return Promise.resolve(); @@ -304,8 +305,7 @@ export class FallbackRecipientHook implements MailDeliverHook {    callback(context: MailDeliverContext) {      if (context.recipients.size === 0) {        context.logger.info( -        "No recipients, fill with fallback: ", -        [...this.fallback].join(" "), +        "No recipients, fill with fallback: " + [...this.fallback].join(", "),        );        this.fallback.forEach((a) => context.recipients.add(a));      } | 
