mirror of
https://github.com/bitwarden/browser
synced 2026-02-10 13:40:06 +00:00
partial work on ecs refactor; not sure it is worth keeping
This commit is contained in:
@@ -1,22 +1,35 @@
|
||||
import { Primitive } from "type-fest";
|
||||
|
||||
/** Elastic Common Schema log format - core fields.
|
||||
*/
|
||||
export interface EcsFormat {
|
||||
"@timestamp": Date,
|
||||
"@timestamp": number;
|
||||
|
||||
/** custom key/value pairs */
|
||||
labels?: Record<string, string>,
|
||||
labels?: Record<string, Primitive>;
|
||||
|
||||
/** system message related to the event */
|
||||
message?: string,
|
||||
message?: string;
|
||||
|
||||
/** keywords tagging the event */
|
||||
tags?: Array<string>,
|
||||
tags?: Array<string>;
|
||||
|
||||
/** describe the event; it is recommended that all events have these. */
|
||||
event: {
|
||||
kind?: "alert" | "enrichment" | "event" | "metric" | "state",
|
||||
category?: "api" | "authentication" | "iam" | "process" | "session" ,
|
||||
type?: "access" | "admin" | "allowed" | "creation" | "deletion" | "denied" | "end" | "error" | "info" | "start" | "user",
|
||||
outcome?: "failure" | "success" | "unknown",
|
||||
}
|
||||
};
|
||||
kind?: "alert" | "enrichment" | "event" | "metric" | "state";
|
||||
category?: "api" | "authentication" | "iam" | "process" | "session";
|
||||
type?:
|
||||
| "access"
|
||||
| "admin"
|
||||
| "allowed"
|
||||
| "creation"
|
||||
| "deletion"
|
||||
| "denied"
|
||||
| "end"
|
||||
| "error"
|
||||
| "info"
|
||||
| "start"
|
||||
| "user";
|
||||
outcome?: "failure" | "success" | "unknown";
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,26 +4,27 @@ import { EcsFormat } from "./core";
|
||||
|
||||
/** extends core event logs with additional information */
|
||||
export type EventFormat = EcsFormat & {
|
||||
|
||||
event: Partial<ProcessEvent> & Partial<ApplicationEvent> & {
|
||||
/** event severity as a number */
|
||||
severity?: LogLevelType,
|
||||
},
|
||||
}
|
||||
action?: string;
|
||||
event: Partial<ProcessEvent> &
|
||||
Partial<ApplicationEvent> & {
|
||||
/** event severity as a number */
|
||||
severity?: LogLevelType;
|
||||
};
|
||||
};
|
||||
|
||||
export type ProcessEvent = {
|
||||
start: Date,
|
||||
duration: number,
|
||||
end: Date,
|
||||
start: Date;
|
||||
duration: number;
|
||||
end: Date;
|
||||
};
|
||||
|
||||
export type ApplicationEvent = {
|
||||
/** source of the event; this is usually a client type or service name */
|
||||
provider: string,
|
||||
/** source of the event; this is usually a client type or service name */
|
||||
provider: string;
|
||||
|
||||
/** reason why the event occurred, according to the source */
|
||||
reason: string,
|
||||
/** reason why the event occurred, according to the source */
|
||||
reason: string;
|
||||
|
||||
/** reference URL for the event */
|
||||
reference: string,
|
||||
/** reference URL for the event */
|
||||
reference: string;
|
||||
};
|
||||
|
||||
23
libs/common/src/tools/log/ecs-format/service.ts
Normal file
23
libs/common/src/tools/log/ecs-format/service.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { EcsFormat } from "./core";
|
||||
|
||||
export type ServiceFormat = EcsFormat & {
|
||||
/** documents the program providing the log */
|
||||
service: {
|
||||
/** Which kind of client is it? */
|
||||
name: "android" | "cli" | "desktop" | "extension" | "ios" | "web";
|
||||
|
||||
/** identifies the service as a type of client device */
|
||||
type: "client";
|
||||
|
||||
/** Information about the instance of the service providing the log */
|
||||
node: {
|
||||
/** a unique identifier(s) for this client installation */
|
||||
name: string;
|
||||
};
|
||||
/** The environment to which the client was connected */
|
||||
environment: "production" | "testing" | "development" | "local";
|
||||
|
||||
/** the unique identifier(s) for this client installation */
|
||||
version: "2025.3.1-innovation-sprint";
|
||||
};
|
||||
};
|
||||
126
libs/common/src/tools/log/ecs-semantic-logger.ts
Normal file
126
libs/common/src/tools/log/ecs-semantic-logger.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import { Subject } from "rxjs";
|
||||
import { Primitive } from "type-fest";
|
||||
|
||||
import { LogService } from "../../platform/abstractions/log.service";
|
||||
import { LogLevelType } from "../../platform/enums";
|
||||
|
||||
import { EcsFormat, ErrorFormat, EventFormat, LogFormat, UserFormat } from "./ecs-format";
|
||||
import { ServiceFormat } from "./ecs-format/service";
|
||||
import { SemanticLogger } from "./semantic-logger.abstraction";
|
||||
|
||||
type ClientInfo = ServiceFormat & { log: { logger: string } };
|
||||
|
||||
export class EcsLogger implements SemanticLogger {
|
||||
constructor(
|
||||
private logger: LogService,
|
||||
private clientInfo: ClientInfo,
|
||||
private now = () => Date.now(),
|
||||
) {
|
||||
this.pipe = new Subject();
|
||||
}
|
||||
|
||||
private pipe: Subject<EcsFormat>;
|
||||
|
||||
log$() {
|
||||
return this.pipe.asObservable();
|
||||
}
|
||||
|
||||
event(info: EventFormat) {}
|
||||
|
||||
debug(labels: Record<string, Primitive> | string, message?: string): void {
|
||||
this.log(labels, LogLevelType.Debug, message);
|
||||
}
|
||||
|
||||
info(labels: Record<string, Primitive> | string, message?: string): void {
|
||||
this.log(labels, LogLevelType.Info, message);
|
||||
}
|
||||
|
||||
warn(labels: Record<string, Primitive> | string, message?: string): void {
|
||||
this.log(labels, LogLevelType.Warning, message);
|
||||
}
|
||||
|
||||
caught(error: Error, labels?: Record<string, Primitive>) {
|
||||
const log: LogFormat & ErrorFormat & Partial<UserFormat> = {
|
||||
...this.clientInfo,
|
||||
error: {
|
||||
message: error.message,
|
||||
stack_trace: error.stack,
|
||||
type: error.name,
|
||||
},
|
||||
labels,
|
||||
event: {
|
||||
kind: "event",
|
||||
category: "process",
|
||||
type: "error",
|
||||
...this.clientInfo.event,
|
||||
},
|
||||
log: {
|
||||
level: stringifyLevel(LogLevelType.Error),
|
||||
...this.clientInfo.log,
|
||||
},
|
||||
"@timestamp": this.now(),
|
||||
};
|
||||
|
||||
this.write(log);
|
||||
}
|
||||
|
||||
error(labels: Record<string, Primitive> | string, message?: string): void {
|
||||
this.log(labels, LogLevelType.Error, message);
|
||||
}
|
||||
|
||||
panic(labels: Record<string, Primitive> | string, message?: string): never {
|
||||
const panicMessage = this.log(labels, LogLevelType.Error, message) ?? "a fatal error occurred";
|
||||
throw new Error(panicMessage);
|
||||
}
|
||||
|
||||
private log(
|
||||
content: Record<string, Primitive> | string,
|
||||
level: LogLevelType,
|
||||
maybeMessage?: string,
|
||||
) {
|
||||
const labels = typeof content === "string" ? { content } : content;
|
||||
const message =
|
||||
maybeMessage ?? (typeof content === "string" ? content : "message not provided");
|
||||
|
||||
const log: LogFormat & EventFormat = {
|
||||
...this.clientInfo,
|
||||
message,
|
||||
labels,
|
||||
event: {
|
||||
kind: "event",
|
||||
category: "process",
|
||||
type: level === LogLevelType.Error ? "error" : "info",
|
||||
severity: level,
|
||||
...this.clientInfo.event,
|
||||
},
|
||||
log: {
|
||||
level: stringifyLevel(level),
|
||||
...this.clientInfo.log,
|
||||
},
|
||||
"@timestamp": this.now(),
|
||||
};
|
||||
|
||||
this.write(log);
|
||||
|
||||
return log.message;
|
||||
}
|
||||
|
||||
private write(event: EcsFormat) {
|
||||
this.pipe.next(event);
|
||||
}
|
||||
}
|
||||
|
||||
function stringifyLevel(level: LogLevelType) {
|
||||
switch (level) {
|
||||
case LogLevelType.Debug:
|
||||
return "debug";
|
||||
case LogLevelType.Info:
|
||||
return "info";
|
||||
case LogLevelType.Warning:
|
||||
return "warn";
|
||||
case LogLevelType.Error:
|
||||
return "error";
|
||||
default:
|
||||
return "info";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user