refactor: unify logging into @gadget/api as GadgetLog
Move the 6 duplicated logging modules (component, log, log-transport, log-transport-console, log-transport-file, log-file) from both gadget-code (Dtp* prefix) and gadget-drone (Gadget* prefix) into @shad/api, using gadget-drone's GadgetLog as the canonical version. GadgetLog now uses static configuration (consoleEnabled, defaultFile) set by each consumer's env.ts at module scope, removing the env dependency from the shared library. The addDefaultTransport/ removeDefaultTransport/getDefaultTransports static methods are preserved for future real-time log transport injection.
This commit is contained in:
parent
58850f36e6
commit
42a47dbcb7
@ -6,6 +6,7 @@ import path, { dirname } from "node:path";
|
|||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { loadGadgetCodeConfig, resolvePath } from "@gadget/config";
|
import { loadGadgetCodeConfig, resolvePath } from "@gadget/config";
|
||||||
import type PackageJson from "../../package.json";
|
import type PackageJson from "../../package.json";
|
||||||
|
import { GadgetLog, GadgetLogFile } from "@gadget/api";
|
||||||
|
|
||||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
@ -179,6 +180,12 @@ export default {
|
|||||||
},
|
},
|
||||||
file: {
|
file: {
|
||||||
enabled: yamlConfig.logging?.file?.enabled === true,
|
enabled: yamlConfig.logging?.file?.enabled === true,
|
||||||
|
path: yamlConfig.logging?.file?.path
|
||||||
|
? resolvePath(yamlConfig.logging.file.path)
|
||||||
|
: path.join(INSTALL_DIR, "logs"),
|
||||||
|
name: yamlConfig.logging?.file?.name || "gadget-code",
|
||||||
|
maxWritesPerFile: yamlConfig.logging?.file?.maxWritesPerFile || 10000,
|
||||||
|
maxFiles: yamlConfig.logging?.file?.maxFiles || 10,
|
||||||
},
|
},
|
||||||
levels: {
|
levels: {
|
||||||
debug: yamlConfig.logging?.levels?.debug === true,
|
debug: yamlConfig.logging?.levels?.debug === true,
|
||||||
@ -187,3 +194,17 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Configure GadgetLog for this package
|
||||||
|
const logFileOptions = {
|
||||||
|
basePath: yamlConfig.logging?.file?.path
|
||||||
|
? resolvePath(yamlConfig.logging.file.path)
|
||||||
|
: path.join(INSTALL_DIR, "logs"),
|
||||||
|
name: yamlConfig.logging?.file?.name || "gadget-code",
|
||||||
|
maxWritesPerFile: yamlConfig.logging?.file?.maxWritesPerFile || 10000,
|
||||||
|
maxFiles: yamlConfig.logging?.file?.maxFiles || 10,
|
||||||
|
};
|
||||||
|
const defaultLogFile = new GadgetLogFile(logFileOptions);
|
||||||
|
defaultLogFile.open();
|
||||||
|
GadgetLog.consoleEnabled = yamlConfig.logging?.console?.enabled === true;
|
||||||
|
GadgetLog.defaultFile = yamlConfig.logging?.file?.enabled === true ? defaultLogFile : undefined;
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
// src/lib/component.ts
|
|
||||||
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
|
|
||||||
// All Rights Reserved
|
|
||||||
|
|
||||||
export interface DtpComponent {
|
|
||||||
get name(): string;
|
|
||||||
get slug(): string;
|
|
||||||
}
|
|
||||||
@ -30,9 +30,8 @@ import { ApiClientStatus } from "../models/api-client.js";
|
|||||||
import { CsrfToken, ICsrfToken } from "../models/csrf-token.js";
|
import { CsrfToken, ICsrfToken } from "../models/csrf-token.js";
|
||||||
import { GadgetId, IUser } from "@gadget/api";
|
import { GadgetId, IUser } from "@gadget/api";
|
||||||
|
|
||||||
import { DtpComponent } from "./component.js";
|
import { GadgetComponent, GadgetLog } from "@gadget/api";
|
||||||
import { DtpPaginationParameters } from "./pagination-parameters.js";
|
import { DtpPaginationParameters } from "./pagination-parameters.js";
|
||||||
import { DtpLog } from "./log.js";
|
|
||||||
|
|
||||||
import ApiClientService from "../services/api-client.js";
|
import ApiClientService from "../services/api-client.js";
|
||||||
import CryptoService from "../services/crypto.js";
|
import CryptoService from "../services/crypto.js";
|
||||||
@ -45,8 +44,8 @@ import CryptoService from "../services/crypto.js";
|
|||||||
* request parameters, headers, and body content, then rendering HTML page or
|
* request parameters, headers, and body content, then rendering HTML page or
|
||||||
* JSON object responses.
|
* JSON object responses.
|
||||||
*/
|
*/
|
||||||
export abstract class DtpController implements DtpComponent {
|
export abstract class DtpController implements GadgetComponent {
|
||||||
log: DtpLog;
|
log: GadgetLog;
|
||||||
router: Router;
|
router: Router;
|
||||||
|
|
||||||
abstract get name(): string;
|
abstract get name(): string;
|
||||||
@ -54,7 +53,7 @@ export abstract class DtpController implements DtpComponent {
|
|||||||
abstract get route(): string;
|
abstract get route(): string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.log = new DtpLog(this);
|
this.log = new GadgetLog(this);
|
||||||
this.router = Router();
|
this.router = Router();
|
||||||
this.router.use(this.middleware.bind(this));
|
this.router.use(this.middleware.bind(this));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import env from "../config/env.js";
|
|||||||
|
|
||||||
import mongoose from "mongoose";
|
import mongoose from "mongoose";
|
||||||
|
|
||||||
import { DtpLog } from "./log.js";
|
import { GadgetLog } from "@gadget/api";
|
||||||
const log = new DtpLog({ name: "db", slug: "db" });
|
const log = new GadgetLog({ name: "db", slug: "db" });
|
||||||
|
|
||||||
const DB_URL = `mongodb://${env.mongodb.host}/${env.mongodb.database}`;
|
const DB_URL = `mongodb://${env.mongodb.host}/${env.mongodb.database}`;
|
||||||
|
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
// src/lib/log-file.ts
|
|
||||||
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
|
|
||||||
// All Rights Reserved
|
|
||||||
|
|
||||||
import fs from "node:fs";
|
|
||||||
import path from "node:path";
|
|
||||||
|
|
||||||
import numeral from "numeral";
|
|
||||||
|
|
||||||
import { Writable, WritableOptions } from "stream";
|
|
||||||
|
|
||||||
type StreamCallback = (error?: Error | null) => void;
|
|
||||||
|
|
||||||
export interface DtpLogFileOptions extends WritableOptions {
|
|
||||||
basePath: string;
|
|
||||||
name: string;
|
|
||||||
maxWritesPerFile: number;
|
|
||||||
maxFiles: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DtpLogFile extends Writable {
|
|
||||||
options: DtpLogFileOptions;
|
|
||||||
file?: fs.WriteStream;
|
|
||||||
|
|
||||||
fileIdx: number = 0;
|
|
||||||
writeCount: number = 0;
|
|
||||||
|
|
||||||
constructor(options: DtpLogFileOptions) {
|
|
||||||
super(options);
|
|
||||||
this.options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
open(): void {
|
|
||||||
fs.mkdirSync(this.options.basePath, { recursive: true });
|
|
||||||
const filename = path.join(
|
|
||||||
this.options.basePath,
|
|
||||||
`${this.options.name}.${numeral(this.fileIdx).format("000")}.log`
|
|
||||||
);
|
|
||||||
this.file = fs.createWriteStream(filename, { encoding: "utf-8" });
|
|
||||||
this.writeCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_write(
|
|
||||||
chunk: unknown,
|
|
||||||
encoding: BufferEncoding,
|
|
||||||
callback: StreamCallback
|
|
||||||
): boolean {
|
|
||||||
if (!this.file) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (this.writeCount > this.options.maxWritesPerFile) {
|
|
||||||
this.file.close();
|
|
||||||
if (++this.fileIdx > this.options.maxFiles) {
|
|
||||||
this.fileIdx = 0;
|
|
||||||
}
|
|
||||||
this.open();
|
|
||||||
}
|
|
||||||
return this.file.write(chunk, encoding, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
// src/lib/log-transport-console.ts
|
|
||||||
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
|
|
||||||
// All Rights Reserved
|
|
||||||
|
|
||||||
import * as util from "node:util";
|
|
||||||
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import color from "ansicolor";
|
|
||||||
|
|
||||||
import { DtpLogLevel } from "./log.js";
|
|
||||||
import { DtpLogTransport } from "./log-transport.js";
|
|
||||||
import { DtpComponent } from "./component.ts";
|
|
||||||
|
|
||||||
export class DtpLogTransportConsole implements DtpLogTransport {
|
|
||||||
async writeLog(
|
|
||||||
timestamp: Date,
|
|
||||||
component: DtpComponent,
|
|
||||||
level: DtpLogLevel,
|
|
||||||
message: string,
|
|
||||||
metadata?: unknown
|
|
||||||
): Promise<void> {
|
|
||||||
let clevel = level.padEnd(5);
|
|
||||||
switch (level) {
|
|
||||||
case "debug":
|
|
||||||
clevel = color.darkGray(clevel);
|
|
||||||
break;
|
|
||||||
case "info":
|
|
||||||
clevel = color.green(clevel);
|
|
||||||
break;
|
|
||||||
case "warn":
|
|
||||||
clevel = color.yellow(clevel);
|
|
||||||
break;
|
|
||||||
case "alert":
|
|
||||||
clevel = color.red(clevel);
|
|
||||||
break;
|
|
||||||
case "error":
|
|
||||||
clevel = color.bgRed.white(clevel);
|
|
||||||
break;
|
|
||||||
case "crit":
|
|
||||||
clevel = color.bgRed.yellow(clevel);
|
|
||||||
break;
|
|
||||||
case "fatal":
|
|
||||||
clevel = color.bgRed.darkGray(clevel);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ccomponent = color.cyan(component.name);
|
|
||||||
const ctimestamp = color.darkGray(
|
|
||||||
dayjs(timestamp).format("YYYY-MM-DD HH:mm:ss.SSS")
|
|
||||||
);
|
|
||||||
const cmessage = color.darkGray(message);
|
|
||||||
|
|
||||||
if (metadata) {
|
|
||||||
console.log(
|
|
||||||
`${ctimestamp} ${clevel} ${ccomponent} ${cmessage}`,
|
|
||||||
util.inspect(metadata, false, Infinity, true)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
console.log(`${ctimestamp} ${clevel} ${ccomponent} ${cmessage}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
// src/lib/log-transport-file.ts
|
|
||||||
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
|
|
||||||
// All Rights Reserved
|
|
||||||
|
|
||||||
import util from "node:util";
|
|
||||||
import { Writable } from "node:stream";
|
|
||||||
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
|
|
||||||
import { DtpLogLevel } from "./log.js";
|
|
||||||
import { DtpLogTransport } from "./log-transport.js";
|
|
||||||
import { DtpComponent } from "./component.ts";
|
|
||||||
|
|
||||||
export class DtpLogTransportFile implements DtpLogTransport {
|
|
||||||
file: Writable;
|
|
||||||
|
|
||||||
constructor(file: Writable) {
|
|
||||||
this.file = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
async writeLog(
|
|
||||||
timestamp: Date,
|
|
||||||
component: DtpComponent,
|
|
||||||
level: DtpLogLevel,
|
|
||||||
message: string,
|
|
||||||
metadata?: unknown,
|
|
||||||
): Promise<void> {
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
|
||||||
const stimestamp = dayjs(timestamp).format("YYYY-MM-DD HH:mm:ss.SSS");
|
|
||||||
|
|
||||||
let sLogMessage = `${stimestamp} ${level} ${component.slug} ${message}`;
|
|
||||||
if (metadata) {
|
|
||||||
sLogMessage += " " + util.inspect(metadata, false, Infinity, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const chunk = Buffer.from(sLogMessage + "\n");
|
|
||||||
this.file.write(chunk, (error: Error | null | undefined): void => {
|
|
||||||
if (error) {
|
|
||||||
return reject(error);
|
|
||||||
}
|
|
||||||
return resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
// src/lib/log-transport.ts
|
|
||||||
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
|
|
||||||
// All Rights Reserved
|
|
||||||
|
|
||||||
import { DtpComponent } from "./component.ts";
|
|
||||||
import { DtpLogLevel } from "./log.js";
|
|
||||||
|
|
||||||
export abstract class DtpLogTransport {
|
|
||||||
abstract writeLog(
|
|
||||||
timestamp: Date,
|
|
||||||
component: DtpComponent,
|
|
||||||
level: DtpLogLevel,
|
|
||||||
message: string,
|
|
||||||
metadata?: unknown
|
|
||||||
): Promise<void>;
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
// src/lib/log.ts
|
|
||||||
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
|
|
||||||
// All Rights Reserved
|
|
||||||
|
|
||||||
import env from "../config/env.js";
|
|
||||||
|
|
||||||
import { DtpComponent } from "./component.ts";
|
|
||||||
import { DtpLogTransportConsole } from "./log-transport-console.js";
|
|
||||||
import { DtpLogTransportFile } from "./log-transport-file.js";
|
|
||||||
import { DtpLogTransport } from "./log-transport.js";
|
|
||||||
import { DtpLogFile } from "./log-file.js";
|
|
||||||
|
|
||||||
export enum DtpLogLevel {
|
|
||||||
debug = "debug",
|
|
||||||
info = "info",
|
|
||||||
warn = "warn",
|
|
||||||
alert = "alert",
|
|
||||||
error = "error",
|
|
||||||
crit = "crit",
|
|
||||||
fatal = "fatal",
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DtpLog {
|
|
||||||
component: DtpComponent;
|
|
||||||
transports: Array<DtpLogTransport> = [];
|
|
||||||
|
|
||||||
constructor(component: DtpComponent, file?: DtpLogFile) {
|
|
||||||
this.component = component;
|
|
||||||
|
|
||||||
if (env.log.console.enabled) {
|
|
||||||
this.transports.push(new DtpLogTransportConsole());
|
|
||||||
}
|
|
||||||
if (env.log.file.enabled && file) {
|
|
||||||
this.transports.push(new DtpLogTransportFile(file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async debug(message: string, metadata?: unknown) {
|
|
||||||
if (!env.log.levels.debug) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return this.writeLog(DtpLogLevel.debug, message, metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
async info(message: string, metadata?: unknown) {
|
|
||||||
if (!env.log.levels.info) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return this.writeLog(DtpLogLevel.info, message, metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
async warn(message: string, metadata?: unknown) {
|
|
||||||
if (!env.log.levels.warn) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return this.writeLog(DtpLogLevel.warn, message, metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
async alert(message: string, metadata?: unknown) {
|
|
||||||
return this.writeLog(DtpLogLevel.alert, message, metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
async error(message: string, metadata?: unknown) {
|
|
||||||
return this.writeLog(DtpLogLevel.error, message, metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
async crit(message: string, metadata?: unknown) {
|
|
||||||
return this.writeLog(DtpLogLevel.crit, message, metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fatal(message: string, metadata?: unknown) {
|
|
||||||
this.writeLog(DtpLogLevel.fatal, message, metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
async writeLog(level: DtpLogLevel, message: string, metadata?: unknown) {
|
|
||||||
const NOW = new Date();
|
|
||||||
for (const transport of this.transports) {
|
|
||||||
transport.writeLog(NOW, this.component, level, message, metadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,16 +2,15 @@
|
|||||||
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
|
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
|
||||||
// All Rights Reserved
|
// All Rights Reserved
|
||||||
|
|
||||||
import { DtpComponent } from "./component.js";
|
import { GadgetComponent, GadgetLog } from "@gadget/api";
|
||||||
import { DtpLog } from "./log.js";
|
|
||||||
|
|
||||||
export abstract class DtpProcess implements DtpComponent {
|
export abstract class DtpProcess implements GadgetComponent {
|
||||||
log: DtpLog;
|
log: GadgetLog;
|
||||||
|
|
||||||
abstract get name(): string;
|
abstract get name(): string;
|
||||||
abstract get slug(): string;
|
abstract get slug(): string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.log = new DtpLog(this);
|
this.log = new GadgetLog(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,8 @@
|
|||||||
import env from "../config/env.js";
|
import env from "../config/env.js";
|
||||||
import { Redis } from "ioredis";
|
import { Redis } from "ioredis";
|
||||||
|
|
||||||
import { DtpLog } from "./log.js";
|
import { GadgetLog } from "@gadget/api";
|
||||||
const log = new DtpLog({ name: "redis", slug: "redis" });
|
const log = new GadgetLog({ name: "redis", slug: "redis" });
|
||||||
|
|
||||||
log.info("connecting to Redis", {
|
log.info("connecting to Redis", {
|
||||||
host: env.redis.host,
|
host: env.redis.host,
|
||||||
|
|||||||
@ -4,17 +4,16 @@
|
|||||||
|
|
||||||
// import env from "../config/env.js";
|
// import env from "../config/env.js";
|
||||||
|
|
||||||
import { DtpComponent } from "./component.js";
|
import { GadgetComponent, GadgetLog } from "@gadget/api";
|
||||||
import { DtpLog } from "./log.js";
|
|
||||||
|
|
||||||
export abstract class DtpService implements DtpComponent {
|
export abstract class DtpService implements GadgetComponent {
|
||||||
log: DtpLog;
|
log: GadgetLog;
|
||||||
|
|
||||||
abstract get name(): string;
|
abstract get name(): string;
|
||||||
abstract get slug(): string;
|
abstract get slug(): string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.log = new DtpLog(this);
|
this.log = new GadgetLog(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract start(): Promise<void>;
|
abstract start(): Promise<void>;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
ServerToClientEvents,
|
ServerToClientEvents,
|
||||||
SocketData,
|
SocketData,
|
||||||
} from "@gadget/api";
|
} from "@gadget/api";
|
||||||
import { DtpLog } from "./log.js";
|
import { GadgetLog } from "@gadget/api";
|
||||||
|
|
||||||
export enum SocketSessionType {
|
export enum SocketSessionType {
|
||||||
Code = "code",
|
Code = "code",
|
||||||
@ -23,7 +23,7 @@ export type GadgetSocket = Socket<
|
|||||||
SocketData
|
SocketData
|
||||||
>;
|
>;
|
||||||
export abstract class SocketSession {
|
export abstract class SocketSession {
|
||||||
protected log: DtpLog;
|
protected log: GadgetLog;
|
||||||
protected _socket: GadgetSocket;
|
protected _socket: GadgetSocket;
|
||||||
protected _user: IUser;
|
protected _user: IUser;
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ export abstract class SocketSession {
|
|||||||
protected abstract type: SocketSessionType;
|
protected abstract type: SocketSessionType;
|
||||||
|
|
||||||
constructor(socket: GadgetSocket, user: IUser) {
|
constructor(socket: GadgetSocket, user: IUser) {
|
||||||
this.log = new DtpLog({
|
this.log = new GadgetLog({
|
||||||
name: "SocketSession",
|
name: "SocketSession",
|
||||||
slug: "lib:socket-session",
|
slug: "lib:socket-session",
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,11 +5,10 @@
|
|||||||
import env from "../config/env.js";
|
import env from "../config/env.js";
|
||||||
import BullQueue from "bull";
|
import BullQueue from "bull";
|
||||||
|
|
||||||
import { DtpLog } from "./log.js";
|
import { GadgetComponent, GadgetLog } from "@gadget/api";
|
||||||
import { DtpComponent } from "./component.js";
|
|
||||||
|
|
||||||
export abstract class DtpWorker implements DtpComponent {
|
export abstract class DtpWorker implements GadgetComponent {
|
||||||
log: DtpLog;
|
log: GadgetLog;
|
||||||
jobQueue: BullQueue.Queue | undefined;
|
jobQueue: BullQueue.Queue | undefined;
|
||||||
|
|
||||||
abstract get name(): string;
|
abstract get name(): string;
|
||||||
@ -17,7 +16,7 @@ export abstract class DtpWorker implements DtpComponent {
|
|||||||
abstract get queueName(): string;
|
abstract get queueName(): string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.log = new DtpLog(this);
|
this.log = new GadgetLog(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
|
|||||||
@ -31,8 +31,7 @@ import numeral from "numeral";
|
|||||||
|
|
||||||
type SameSiteOption = boolean | "lax" | "strict" | "none" | undefined;
|
type SameSiteOption = boolean | "lax" | "strict" | "none" | undefined;
|
||||||
|
|
||||||
import { DtpLog } from "./lib/log.js";
|
import { GadgetComponent, GadgetLog } from "@gadget/api";
|
||||||
import { DtpComponent } from "./lib/component.js";
|
|
||||||
|
|
||||||
import { User } from "./models/user.js";
|
import { User } from "./models/user.js";
|
||||||
|
|
||||||
@ -50,8 +49,8 @@ import {
|
|||||||
} from "./services/index.js";
|
} from "./services/index.js";
|
||||||
import { SessionType } from "./services/session.js";
|
import { SessionType } from "./services/session.js";
|
||||||
|
|
||||||
class DtpWebAppServer implements DtpComponent {
|
class DtpWebAppServer implements GadgetComponent {
|
||||||
private log: DtpLog;
|
private log: GadgetLog;
|
||||||
|
|
||||||
private app?: express.Application;
|
private app?: express.Application;
|
||||||
private server?: http.Server;
|
private server?: http.Server;
|
||||||
@ -64,7 +63,7 @@ class DtpWebAppServer implements DtpComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.log = new DtpLog(this);
|
this.log = new GadgetLog(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import path, { dirname } from "node:path";
|
|||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { loadGadgetDroneConfig, resolvePath } from "@gadget/config";
|
import { loadGadgetDroneConfig, resolvePath } from "@gadget/config";
|
||||||
import type PackageJson from "../../package.json";
|
import type PackageJson from "../../package.json";
|
||||||
|
import { GadgetLog, GadgetLogFile } from "@gadget/api";
|
||||||
|
|
||||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
@ -73,4 +74,19 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Configure GadgetLog for this package
|
||||||
|
const logFileOptions = {
|
||||||
|
basePath: yamlConfig.logging?.file?.path
|
||||||
|
? resolvePath(yamlConfig.logging.file.path)
|
||||||
|
: path.join(INSTALL_DIR, "logs"),
|
||||||
|
name: yamlConfig.logging?.file?.name || "gadget-drone",
|
||||||
|
maxWritesPerFile: yamlConfig.logging?.file?.maxWritesPerFile || 10000,
|
||||||
|
maxFiles: yamlConfig.logging?.file?.maxFiles || 10,
|
||||||
|
};
|
||||||
|
const defaultLogFile = new GadgetLogFile(logFileOptions);
|
||||||
|
defaultLogFile.open();
|
||||||
|
GadgetLog.consoleEnabled = yamlConfig.logging?.console?.enabled === true;
|
||||||
|
GadgetLog.defaultFile = yamlConfig.logging?.file?.enabled === true ? defaultLogFile : undefined;
|
||||||
|
|
||||||
/* eslint-enable no-process-env */
|
/* eslint-enable no-process-env */
|
||||||
|
|||||||
@ -2,8 +2,7 @@
|
|||||||
// Copyright (C) 2026 Rob Colbert <rob.colbert@openplatform.us>
|
// Copyright (C) 2026 Rob Colbert <rob.colbert@openplatform.us>
|
||||||
// Licensed under the Apache License, Version 2.0
|
// Licensed under the Apache License, Version 2.0
|
||||||
|
|
||||||
import { GadgetComponent } from "./component.ts";
|
import { GadgetComponent, GadgetLog } from "@gadget/api";
|
||||||
import { GadgetLog } from "./log.ts";
|
|
||||||
|
|
||||||
export abstract class GadgetProcess implements GadgetComponent {
|
export abstract class GadgetProcess implements GadgetComponent {
|
||||||
protected log: GadgetLog;
|
protected log: GadgetLog;
|
||||||
|
|||||||
@ -4,8 +4,7 @@
|
|||||||
|
|
||||||
// import env from "../config/env.js";
|
// import env from "../config/env.js";
|
||||||
|
|
||||||
import { GadgetComponent } from "./component.js";
|
import { GadgetComponent, GadgetLog } from "@gadget/api";
|
||||||
import { GadgetLog } from "./log.js";
|
|
||||||
|
|
||||||
export abstract class GadgetService implements GadgetComponent {
|
export abstract class GadgetService implements GadgetComponent {
|
||||||
protected log: GadgetLog;
|
protected log: GadgetLog;
|
||||||
|
|||||||
@ -19,10 +19,14 @@
|
|||||||
"author": "Rob Colbert",
|
"author": "Rob Colbert",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mongoose": "^8.16.1"
|
"ansicolor": "^2.0.3",
|
||||||
|
"dayjs": "^1.11.20",
|
||||||
|
"mongoose": "^8.16.1",
|
||||||
|
"numeral": "^2.0.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^25.6.0",
|
"@types/node": "^25.6.0",
|
||||||
|
"@types/numeral": "^2.0.5",
|
||||||
"typescript": "^6.0.3"
|
"typescript": "^6.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,6 +3,12 @@
|
|||||||
// All Rights Reserved
|
// All Rights Reserved
|
||||||
|
|
||||||
export * from "./lib/gadget-id.ts";
|
export * from "./lib/gadget-id.ts";
|
||||||
|
export * from "./lib/component.ts";
|
||||||
|
export * from "./lib/log.ts";
|
||||||
|
export * from "./lib/log-transport.ts";
|
||||||
|
export * from "./lib/log-transport-console.ts";
|
||||||
|
export * from "./lib/log-transport-file.ts";
|
||||||
|
export * from "./lib/log-file.ts";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Data Model Interfaces
|
* Data Model Interfaces
|
||||||
|
|||||||
@ -2,8 +2,6 @@
|
|||||||
// Copyright (C) 2026 Rob Colbert <rob.colbert@openplatform.us>
|
// Copyright (C) 2026 Rob Colbert <rob.colbert@openplatform.us>
|
||||||
// Licensed under the Apache License, Version 2.0
|
// Licensed under the Apache License, Version 2.0
|
||||||
|
|
||||||
import env from "../config/env.js";
|
|
||||||
|
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
@ -60,14 +58,3 @@ export class GadgetLogFile extends Writable {
|
|||||||
return this.file.write(chunk, encoding, callback);
|
return this.file.write(chunk, encoding, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultLogFileOptions = {
|
|
||||||
basePath: env.log.file.path || "/var/log/gadget-code",
|
|
||||||
name: env.log.file.name || env.pkg.name,
|
|
||||||
maxWritesPerFile: env.log.file.maxWritesPerFile,
|
|
||||||
maxFiles: env.log.file.maxFiles,
|
|
||||||
};
|
|
||||||
const defaultLogFile = new GadgetLogFile(defaultLogFileOptions);
|
|
||||||
defaultLogFile.open();
|
|
||||||
|
|
||||||
export { defaultLogFile };
|
|
||||||
@ -7,8 +7,8 @@ import * as util from "node:util";
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import color from "ansicolor";
|
import color from "ansicolor";
|
||||||
|
|
||||||
import { GadgetLogLevel } from "./log.js";
|
import { GadgetLogLevel } from "./log.ts";
|
||||||
import { GadgetLogTransport } from "./log-transport.js";
|
import { GadgetLogTransport } from "./log-transport.ts";
|
||||||
import { GadgetComponent } from "./component.ts";
|
import { GadgetComponent } from "./component.ts";
|
||||||
|
|
||||||
export class GadgetLogTransportConsole implements GadgetLogTransport {
|
export class GadgetLogTransportConsole implements GadgetLogTransport {
|
||||||
@ -7,8 +7,8 @@ import { Writable } from "node:stream";
|
|||||||
|
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
import { GadgetLogLevel } from "./log.js";
|
import { GadgetLogLevel } from "./log.ts";
|
||||||
import { GadgetLogTransport } from "./log-transport.js";
|
import { GadgetLogTransport } from "./log-transport.ts";
|
||||||
import { GadgetComponent } from "./component.ts";
|
import { GadgetComponent } from "./component.ts";
|
||||||
|
|
||||||
export class GadgetLogTransportFile implements GadgetLogTransport {
|
export class GadgetLogTransportFile implements GadgetLogTransport {
|
||||||
@ -3,7 +3,7 @@
|
|||||||
// Licensed under the Apache License, Version 2.0
|
// Licensed under the Apache License, Version 2.0
|
||||||
|
|
||||||
import { GadgetComponent } from "./component.ts";
|
import { GadgetComponent } from "./component.ts";
|
||||||
import { GadgetLogLevel } from "./log.js";
|
import { GadgetLogLevel } from "./log.ts";
|
||||||
|
|
||||||
export abstract class GadgetLogTransport {
|
export abstract class GadgetLogTransport {
|
||||||
abstract writeLog(
|
abstract writeLog(
|
||||||
@ -2,13 +2,11 @@
|
|||||||
// Copyright (C) 2026 Rob Colbert <rob.colbert@openplatform.us>
|
// Copyright (C) 2026 Rob Colbert <rob.colbert@openplatform.us>
|
||||||
// Licensed under the Apache License, Version 2.0
|
// Licensed under the Apache License, Version 2.0
|
||||||
|
|
||||||
import env from "../config/env.js";
|
|
||||||
|
|
||||||
import { GadgetComponent } from "./component.ts";
|
import { GadgetComponent } from "./component.ts";
|
||||||
import { GadgetLogTransportConsole } from "./log-transport-console.js";
|
import { GadgetLogTransportConsole } from "./log-transport-console.ts";
|
||||||
import { GadgetLogTransportFile } from "./log-transport-file.js";
|
import { GadgetLogTransportFile } from "./log-transport-file.ts";
|
||||||
import { GadgetLogTransport } from "./log-transport.js";
|
import { GadgetLogTransport } from "./log-transport.ts";
|
||||||
import { GadgetLogFile, defaultLogFile } from "./log-file.js";
|
import { GadgetLogFile } from "./log-file.ts";
|
||||||
|
|
||||||
export enum GadgetLogLevel {
|
export enum GadgetLogLevel {
|
||||||
debug = "debug",
|
debug = "debug",
|
||||||
@ -25,18 +23,21 @@ export class GadgetLog {
|
|||||||
transports: GadgetLogTransport[] = [];
|
transports: GadgetLogTransport[] = [];
|
||||||
|
|
||||||
private static defaultTransports: GadgetLogTransport[] = [];
|
private static defaultTransports: GadgetLogTransport[] = [];
|
||||||
private file: GadgetLogFile;
|
|
||||||
|
static consoleEnabled = true;
|
||||||
|
static defaultFile: GadgetLogFile | undefined;
|
||||||
|
|
||||||
constructor(component: GadgetComponent, file?: GadgetLogFile) {
|
constructor(component: GadgetComponent, file?: GadgetLogFile) {
|
||||||
this.component = component;
|
this.component = component;
|
||||||
this.file = file || defaultLogFile;
|
|
||||||
this.transports.push(...GadgetLog.defaultTransports);
|
this.transports.push(...GadgetLog.defaultTransports);
|
||||||
|
|
||||||
if (env.log.console.enabled) {
|
if (GadgetLog.consoleEnabled) {
|
||||||
this.transports.push(new GadgetLogTransportConsole());
|
this.transports.push(new GadgetLogTransportConsole());
|
||||||
}
|
}
|
||||||
if (env.log.file.enabled) {
|
|
||||||
this.transports.push(new GadgetLogTransportFile(this.file));
|
const fileInstance = file || GadgetLog.defaultFile;
|
||||||
|
if (fileInstance) {
|
||||||
|
this.transports.push(new GadgetLogTransportFile(fileInstance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,23 +57,17 @@ export class GadgetLog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async debug(message: string, metadata?: unknown) {
|
async debug(message: string, metadata?: unknown) {
|
||||||
if (!env.log.levels.debug) {
|
if (!GadgetLog.consoleEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return this.writeLog(GadgetLogLevel.debug, message, metadata);
|
return this.writeLog(GadgetLogLevel.debug, message, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
async info(message: string, metadata?: unknown) {
|
async info(message: string, metadata?: unknown) {
|
||||||
if (!env.log.levels.info) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return this.writeLog(GadgetLogLevel.info, message, metadata);
|
return this.writeLog(GadgetLogLevel.info, message, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
async warn(message: string, metadata?: unknown) {
|
async warn(message: string, metadata?: unknown) {
|
||||||
if (!env.log.levels.warn) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return this.writeLog(GadgetLogLevel.warn, message, metadata);
|
return this.writeLog(GadgetLogLevel.warn, message, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,6 +67,8 @@ export interface GadgetCodeConfig {
|
|||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
path?: string;
|
path?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
maxWritesPerFile?: number;
|
||||||
|
maxFiles?: number;
|
||||||
};
|
};
|
||||||
https?: {
|
https?: {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
|
|||||||
@ -343,13 +343,25 @@ importers:
|
|||||||
|
|
||||||
packages/api:
|
packages/api:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
ansicolor:
|
||||||
|
specifier: ^2.0.3
|
||||||
|
version: 2.0.3
|
||||||
|
dayjs:
|
||||||
|
specifier: ^1.11.20
|
||||||
|
version: 1.11.20
|
||||||
mongoose:
|
mongoose:
|
||||||
specifier: ^8.16.1
|
specifier: ^8.16.1
|
||||||
version: 8.23.1
|
version: 8.23.1
|
||||||
|
numeral:
|
||||||
|
specifier: ^2.0.6
|
||||||
|
version: 2.0.6
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^25.6.0
|
specifier: ^25.6.0
|
||||||
version: 25.6.0
|
version: 25.6.0
|
||||||
|
'@types/numeral':
|
||||||
|
specifier: ^2.0.5
|
||||||
|
version: 2.0.5
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3
|
version: 6.0.3
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user