mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
refactor: use abstract logger to reduce duplicate code (#9751)
* feat(platform-tools): add more logging functions * refactor(logger): add `AbstractLogger` to reduce duplicate code --------- Co-authored-by: Christian Forgács <christian@wunderbit.de>
This commit is contained in:
parent
9bd3a641cc
commit
12fdd73e25
@ -115,6 +115,64 @@ export class MyCustomLogger implements Logger {
|
||||
}
|
||||
```
|
||||
|
||||
Or you can extend the `AbstractLogger` class:
|
||||
|
||||
```typescript
|
||||
import { AbstractLogger } from "typeorm"
|
||||
|
||||
export class MyCustomLogger implements AbstractLogger {
|
||||
/**
|
||||
* Write log to specific output.
|
||||
*/
|
||||
protected writeLog(
|
||||
level: LogLevel,
|
||||
logMessage: LogMessage | LogMessage[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
const messages = this.prepareLogMessages(logMessage, {
|
||||
highlightSql: false,
|
||||
})
|
||||
|
||||
for (let message of messages) {
|
||||
switch (message.type ?? level) {
|
||||
case "log":
|
||||
case "schema-build":
|
||||
case "migration":
|
||||
console.log(message.message)
|
||||
break
|
||||
|
||||
case "info":
|
||||
case "query":
|
||||
if (message.prefix) {
|
||||
console.info(message.prefix, message.message)
|
||||
} else {
|
||||
console.info(message.message)
|
||||
}
|
||||
break
|
||||
|
||||
case "warn":
|
||||
case "query-slow":
|
||||
if (message.prefix) {
|
||||
console.warn(message.prefix, message.message)
|
||||
} else {
|
||||
console.warn(message.message)
|
||||
}
|
||||
break
|
||||
|
||||
case "error":
|
||||
case "query-error":
|
||||
if (message.prefix) {
|
||||
console.error(message.prefix, message.message)
|
||||
} else {
|
||||
console.error(message.message)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And specify it in data source options:
|
||||
|
||||
```typescript
|
||||
|
||||
@ -97,6 +97,7 @@ export * from "./find-options/FindOptionsWhere"
|
||||
export * from "./find-options/FindTreeOptions"
|
||||
export * from "./find-options/JoinOptions"
|
||||
export * from "./find-options/OrderByCondition"
|
||||
export * from "./logger/AbstractLogger"
|
||||
export * from "./logger/Logger"
|
||||
export * from "./logger/LoggerOptions"
|
||||
export * from "./logger/AdvancedConsoleLogger"
|
||||
|
||||
354
src/logger/AbstractLogger.ts
Normal file
354
src/logger/AbstractLogger.ts
Normal file
@ -0,0 +1,354 @@
|
||||
import {
|
||||
Logger,
|
||||
LogLevel,
|
||||
LogMessage,
|
||||
LogMessageType,
|
||||
PrepareLogMessagesOptions,
|
||||
} from "./Logger"
|
||||
import { QueryRunner } from "../query-runner/QueryRunner"
|
||||
import { LoggerOptions } from "./LoggerOptions"
|
||||
import { PlatformTools } from "../platform/PlatformTools"
|
||||
|
||||
export abstract class AbstractLogger implements Logger {
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(protected options?: LoggerOptions) {}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Logs query and parameters used in it.
|
||||
*/
|
||||
logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner) {
|
||||
if (!this.isLogEnabledFor("query")) {
|
||||
return
|
||||
}
|
||||
|
||||
this.writeLog(
|
||||
"query",
|
||||
{
|
||||
type: "query",
|
||||
prefix: "query",
|
||||
message: query,
|
||||
format: "sql",
|
||||
parameters,
|
||||
},
|
||||
queryRunner,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs query that is failed.
|
||||
*/
|
||||
logQueryError(
|
||||
error: string,
|
||||
query: string,
|
||||
parameters?: any[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
if (!this.isLogEnabledFor("query-error")) {
|
||||
return
|
||||
}
|
||||
|
||||
this.writeLog(
|
||||
"warn",
|
||||
[
|
||||
{
|
||||
type: "query-error",
|
||||
prefix: "query failed",
|
||||
message: query,
|
||||
format: "sql",
|
||||
parameters,
|
||||
},
|
||||
{
|
||||
type: "query-error",
|
||||
prefix: "error",
|
||||
message: error,
|
||||
},
|
||||
],
|
||||
queryRunner,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs query that is slow.
|
||||
*/
|
||||
logQuerySlow(
|
||||
time: number,
|
||||
query: string,
|
||||
parameters?: any[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
if (!this.isLogEnabledFor("query-slow")) {
|
||||
return
|
||||
}
|
||||
|
||||
this.writeLog(
|
||||
"warn",
|
||||
[
|
||||
{
|
||||
type: "query-slow",
|
||||
prefix: "query is slow",
|
||||
message: query,
|
||||
format: "sql",
|
||||
parameters,
|
||||
additionalInfo: {
|
||||
time,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "query-slow",
|
||||
prefix: "execution time",
|
||||
message: time,
|
||||
},
|
||||
],
|
||||
queryRunner,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs events from the schema build process.
|
||||
*/
|
||||
logSchemaBuild(message: string, queryRunner?: QueryRunner) {
|
||||
if (!this.isLogEnabledFor("schema-build")) {
|
||||
return
|
||||
}
|
||||
|
||||
this.writeLog(
|
||||
"schema",
|
||||
{
|
||||
type: "schema-build",
|
||||
message,
|
||||
},
|
||||
queryRunner,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs events from the migration run process.
|
||||
*/
|
||||
logMigration(message: string, queryRunner?: QueryRunner) {
|
||||
if (this.isLogEnabledFor("migration")) {
|
||||
return
|
||||
}
|
||||
|
||||
this.writeLog(
|
||||
"log",
|
||||
{
|
||||
type: "migration",
|
||||
message,
|
||||
},
|
||||
queryRunner,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform logging using given logger, or by default to the console.
|
||||
* Log has its own level and message.
|
||||
*/
|
||||
log(
|
||||
level: "log" | "info" | "warn",
|
||||
message: any,
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
switch (level) {
|
||||
case "log":
|
||||
if (!this.isLogEnabledFor("log")) {
|
||||
return
|
||||
}
|
||||
|
||||
this.writeLog(
|
||||
"log",
|
||||
{
|
||||
type: "log",
|
||||
message,
|
||||
},
|
||||
queryRunner,
|
||||
)
|
||||
break
|
||||
|
||||
case "info":
|
||||
if (!this.isLogEnabledFor("info")) {
|
||||
return
|
||||
}
|
||||
|
||||
this.writeLog(
|
||||
"info",
|
||||
{
|
||||
type: "info",
|
||||
prefix: "info",
|
||||
message,
|
||||
},
|
||||
queryRunner,
|
||||
)
|
||||
break
|
||||
|
||||
case "warn":
|
||||
if (!this.isLogEnabledFor("warn")) {
|
||||
return
|
||||
}
|
||||
|
||||
this.writeLog(
|
||||
"warn",
|
||||
{
|
||||
type: "warn",
|
||||
message,
|
||||
},
|
||||
queryRunner,
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Protected Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Check is logging for level or message type is enabled.
|
||||
*/
|
||||
protected isLogEnabledFor(type?: LogLevel | LogMessageType) {
|
||||
switch (type) {
|
||||
case "query":
|
||||
return (
|
||||
this.options === "all" ||
|
||||
this.options === true ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("query") !== -1)
|
||||
)
|
||||
|
||||
case "error":
|
||||
case "query-error":
|
||||
return (
|
||||
this.options === "all" ||
|
||||
this.options === true ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("error") !== -1)
|
||||
)
|
||||
|
||||
case "query-slow":
|
||||
return true
|
||||
|
||||
case "schema":
|
||||
case "schema-build":
|
||||
return (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("schema") !== -1)
|
||||
)
|
||||
|
||||
case "migration":
|
||||
return true
|
||||
|
||||
case "log":
|
||||
return (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("log") !== -1)
|
||||
)
|
||||
|
||||
case "info":
|
||||
return (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("info") !== -1)
|
||||
)
|
||||
|
||||
case "warn":
|
||||
return (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("warn") !== -1)
|
||||
)
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write log to specific output.
|
||||
*/
|
||||
protected abstract writeLog(
|
||||
level: LogLevel,
|
||||
message:
|
||||
| LogMessage
|
||||
| string
|
||||
| number
|
||||
| (LogMessage | string | number)[],
|
||||
queryRunner?: QueryRunner,
|
||||
): void
|
||||
|
||||
/**
|
||||
* Prepare and format log messages
|
||||
*/
|
||||
protected prepareLogMessages(
|
||||
logMessage:
|
||||
| LogMessage
|
||||
| string
|
||||
| number
|
||||
| (LogMessage | string | number)[],
|
||||
options?: Partial<PrepareLogMessagesOptions>,
|
||||
): LogMessage[] {
|
||||
options = {
|
||||
...{
|
||||
addColonToPrefix: true,
|
||||
appendParameterAsComment: true,
|
||||
highlightSql: true,
|
||||
},
|
||||
...options,
|
||||
}
|
||||
const messages = Array.isArray(logMessage) ? logMessage : [logMessage]
|
||||
|
||||
for (let message of messages) {
|
||||
if (typeof message !== "object") {
|
||||
message = {
|
||||
message,
|
||||
}
|
||||
}
|
||||
|
||||
if (message.format === "sql") {
|
||||
let sql = String(message.message)
|
||||
|
||||
if (
|
||||
options.appendParameterAsComment &&
|
||||
message.parameters &&
|
||||
message.parameters.length
|
||||
) {
|
||||
sql += ` -- PARAMETERS: ${this.stringifyParams(
|
||||
message.parameters,
|
||||
)}`
|
||||
}
|
||||
|
||||
if (options.highlightSql) {
|
||||
sql = PlatformTools.highlightSql(sql)
|
||||
}
|
||||
|
||||
message.message = sql
|
||||
}
|
||||
|
||||
if (options.addColonToPrefix && message.prefix) {
|
||||
message.prefix += ":"
|
||||
}
|
||||
}
|
||||
|
||||
return messages as LogMessage[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts parameters to a string.
|
||||
* Sometimes parameters can have circular objects and therefor we are handle this case too.
|
||||
*/
|
||||
protected stringifyParams(parameters: any[]) {
|
||||
try {
|
||||
return JSON.stringify(parameters)
|
||||
} catch (error) {
|
||||
// most probably circular objects in parameters
|
||||
return parameters
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,159 +1,65 @@
|
||||
import { LoggerOptions } from "./LoggerOptions"
|
||||
import { PlatformTools } from "../platform/PlatformTools"
|
||||
import { AbstractLogger } from "./AbstractLogger"
|
||||
import { LogLevel, LogMessage } from "./Logger"
|
||||
import { QueryRunner } from "../query-runner/QueryRunner"
|
||||
import { Logger } from "./Logger"
|
||||
|
||||
/**
|
||||
* Performs logging of the events in TypeORM.
|
||||
* This version of logger uses console to log events and use syntax highlighting.
|
||||
*/
|
||||
export class AdvancedConsoleLogger implements Logger {
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(private options?: LoggerOptions) {}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
export class AdvancedConsoleLogger extends AbstractLogger {
|
||||
/**
|
||||
* Logs query and parameters used in it.
|
||||
* Write log to specific output.
|
||||
*/
|
||||
logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner) {
|
||||
if (
|
||||
this.options === "all" ||
|
||||
this.options === true ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("query") !== -1)
|
||||
) {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? " -- PARAMETERS: " + this.stringifyParams(parameters)
|
||||
: "")
|
||||
PlatformTools.logInfo("query:", PlatformTools.highlightSql(sql))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs query that is failed.
|
||||
*/
|
||||
logQueryError(
|
||||
error: string,
|
||||
query: string,
|
||||
parameters?: any[],
|
||||
protected writeLog(
|
||||
level: LogLevel,
|
||||
logMessage: LogMessage | LogMessage[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
if (
|
||||
this.options === "all" ||
|
||||
this.options === true ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("error") !== -1)
|
||||
) {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? " -- PARAMETERS: " + this.stringifyParams(parameters)
|
||||
: "")
|
||||
PlatformTools.logError(
|
||||
`query failed:`,
|
||||
PlatformTools.highlightSql(sql),
|
||||
)
|
||||
PlatformTools.logError(`error:`, error)
|
||||
}
|
||||
}
|
||||
const messages = this.prepareLogMessages(logMessage)
|
||||
|
||||
/**
|
||||
* Logs query that is slow.
|
||||
*/
|
||||
logQuerySlow(
|
||||
time: number,
|
||||
query: string,
|
||||
parameters?: any[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? " -- PARAMETERS: " + this.stringifyParams(parameters)
|
||||
: "")
|
||||
PlatformTools.logWarn(`query is slow:`, PlatformTools.highlightSql(sql))
|
||||
PlatformTools.logWarn(`execution time:`, time)
|
||||
}
|
||||
for (let message of messages) {
|
||||
switch (message.type ?? level) {
|
||||
case "log":
|
||||
case "schema-build":
|
||||
case "migration":
|
||||
PlatformTools.log(String(message.message))
|
||||
break
|
||||
|
||||
/**
|
||||
* Logs events from the schema build process.
|
||||
*/
|
||||
logSchemaBuild(message: string, queryRunner?: QueryRunner) {
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("schema") !== -1)
|
||||
) {
|
||||
PlatformTools.log(message)
|
||||
}
|
||||
}
|
||||
case "info":
|
||||
case "query":
|
||||
if (message.prefix) {
|
||||
PlatformTools.logInfo(message.prefix, message.message)
|
||||
} else {
|
||||
PlatformTools.log(String(message.message))
|
||||
}
|
||||
break
|
||||
|
||||
/**
|
||||
* Logs events from the migration run process.
|
||||
*/
|
||||
logMigration(message: string, queryRunner?: QueryRunner) {
|
||||
PlatformTools.log(message)
|
||||
}
|
||||
case "warn":
|
||||
case "query-slow":
|
||||
if (message.prefix) {
|
||||
PlatformTools.logWarn(message.prefix, message.message)
|
||||
} else {
|
||||
console.warn(
|
||||
PlatformTools.warn(String(message.message)),
|
||||
)
|
||||
}
|
||||
break
|
||||
|
||||
/**
|
||||
* Perform logging using given logger, or by default to the console.
|
||||
* Log has its own level and message.
|
||||
*/
|
||||
log(
|
||||
level: "log" | "info" | "warn",
|
||||
message: any,
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
switch (level) {
|
||||
case "log":
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("log") !== -1)
|
||||
)
|
||||
PlatformTools.log(message)
|
||||
break
|
||||
case "info":
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("info") !== -1)
|
||||
)
|
||||
PlatformTools.logInfo("INFO:", message)
|
||||
break
|
||||
case "warn":
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("warn") !== -1)
|
||||
)
|
||||
console.warn(PlatformTools.warn(message))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Protected Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Converts parameters to a string.
|
||||
* Sometimes parameters can have circular objects and therefore we are handle this case too.
|
||||
*/
|
||||
protected stringifyParams(parameters: any[]) {
|
||||
try {
|
||||
return JSON.stringify(parameters)
|
||||
} catch (error) {
|
||||
// most probably circular objects in parameters
|
||||
return parameters
|
||||
case "error":
|
||||
case "query-error":
|
||||
if (message.prefix) {
|
||||
PlatformTools.logError(
|
||||
message.prefix,
|
||||
String(message.message),
|
||||
)
|
||||
} else {
|
||||
console.error(
|
||||
PlatformTools.error(String(message.message)),
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,113 +1,94 @@
|
||||
import debug from "debug"
|
||||
import { Logger } from "./Logger"
|
||||
import { AbstractLogger } from "./AbstractLogger"
|
||||
import { debug, Debugger } from "debug"
|
||||
import { LogLevel, LogMessage, LogMessageType } from "./Logger"
|
||||
import { QueryRunner } from "../query-runner/QueryRunner"
|
||||
import { PlatformTools } from "../platform/PlatformTools"
|
||||
|
||||
/**
|
||||
* Performs logging of the events in TypeORM via debug library.
|
||||
*/
|
||||
export class DebugLogger implements Logger {
|
||||
private debugQueryLog = debug("typeorm:query:log")
|
||||
private debugQueryError = debug("typeorm:query:error")
|
||||
private debugQuerySlow = debug("typeorm:query:slow")
|
||||
private debugSchemaBuild = debug("typeorm:schema")
|
||||
private debugMigration = debug("typeorm:migration")
|
||||
|
||||
private debugLog = debug("typeorm:log")
|
||||
private debugInfo = debug("typeorm:info")
|
||||
private debugWarn = debug("typeorm:warn")
|
||||
|
||||
export class DebugLogger extends AbstractLogger {
|
||||
/**
|
||||
* Logs query and parameters used in it.
|
||||
* Object with all debug logger.
|
||||
*/
|
||||
logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner) {
|
||||
if (this.debugQueryLog.enabled) {
|
||||
this.debugQueryLog(PlatformTools.highlightSql(query) + ";")
|
||||
if (parameters && parameters.length) {
|
||||
this.debugQueryLog("parameters:", parameters)
|
||||
}
|
||||
}
|
||||
private logger: Record<string, Debugger> = {
|
||||
log: debug("typeorm:log"),
|
||||
info: debug("typeorm:info"),
|
||||
warn: debug("typeorm:warn"),
|
||||
error: debug("typeorm:error"),
|
||||
query: debug("typeorm:query:log"),
|
||||
"query-error": debug("typeorm:query:error"),
|
||||
"query-slow": debug("typeorm:query:slow"),
|
||||
"schema-build": debug("typeorm:schema"),
|
||||
migration: debug("typeorm:migration"),
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs query that failed.
|
||||
* Check is logging for level or message type is enabled.
|
||||
*/
|
||||
logQueryError(
|
||||
error: string,
|
||||
query: string,
|
||||
parameters?: any[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
if (this.debugQueryError.enabled) {
|
||||
this.debugQueryError(PlatformTools.highlightSql(query) + ";")
|
||||
if (parameters && parameters.length) {
|
||||
this.debugQueryError("parameters:", parameters)
|
||||
}
|
||||
this.debugQueryError("error: ", error)
|
||||
}
|
||||
}
|
||||
protected isLogEnabledFor(type?: LogLevel | LogMessageType) {
|
||||
switch (type) {
|
||||
case "query":
|
||||
return this.logger["query"].enabled
|
||||
|
||||
/**
|
||||
* Logs query that is slow.
|
||||
*/
|
||||
logQuerySlow(
|
||||
time: number,
|
||||
query: string,
|
||||
parameters?: any[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
if (this.debugQuerySlow.enabled) {
|
||||
this.debugQuerySlow(PlatformTools.highlightSql(query) + ";")
|
||||
if (parameters && parameters.length) {
|
||||
this.debugQuerySlow("parameters:", parameters)
|
||||
}
|
||||
this.debugQuerySlow("execution time:", time)
|
||||
}
|
||||
}
|
||||
case "query-error":
|
||||
return this.logger["query-error"].enabled
|
||||
|
||||
/**
|
||||
* Logs events from the schema build process.
|
||||
*/
|
||||
logSchemaBuild(message: string, queryRunner?: QueryRunner) {
|
||||
if (this.debugSchemaBuild.enabled) {
|
||||
this.debugSchemaBuild(message)
|
||||
}
|
||||
}
|
||||
case "query-slow":
|
||||
return true
|
||||
|
||||
/**
|
||||
* Logs events from the migration run process.
|
||||
*/
|
||||
logMigration(message: string, queryRunner?: QueryRunner) {
|
||||
if (this.debugMigration.enabled) {
|
||||
this.debugMigration(message)
|
||||
}
|
||||
}
|
||||
case "schema":
|
||||
case "schema-build":
|
||||
return this.logger["schema-build"].enabled
|
||||
|
||||
case "migration":
|
||||
return this.logger["migration"].enabled
|
||||
|
||||
/**
|
||||
* Perform logging using given logger.
|
||||
* Log has its own level and message.
|
||||
*/
|
||||
log(
|
||||
level: "log" | "info" | "warn",
|
||||
message: any,
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
switch (level) {
|
||||
case "log":
|
||||
if (this.debugLog.enabled) {
|
||||
this.debugLog(message)
|
||||
}
|
||||
break
|
||||
return this.logger["log"].enabled
|
||||
|
||||
case "info":
|
||||
if (this.debugInfo.enabled) {
|
||||
this.debugInfo(message)
|
||||
}
|
||||
break
|
||||
return this.logger["info"].enabled
|
||||
|
||||
case "warn":
|
||||
if (this.debugWarn.enabled) {
|
||||
this.debugWarn(message)
|
||||
return this.logger["warn"].enabled
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write log to specific output.
|
||||
*/
|
||||
protected writeLog(
|
||||
level: LogLevel,
|
||||
logMessage: LogMessage | LogMessage[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
const messages = this.prepareLogMessages(logMessage, {
|
||||
appendParameterAsComment: false,
|
||||
})
|
||||
|
||||
for (let message of messages) {
|
||||
const messageTypeOrLevel = message.type ?? level
|
||||
|
||||
if (messageTypeOrLevel in this.logger) {
|
||||
if (message.prefix) {
|
||||
this.logger[messageTypeOrLevel](
|
||||
message.prefix,
|
||||
message.message,
|
||||
)
|
||||
} else {
|
||||
this.logger[messageTypeOrLevel](message.message)
|
||||
}
|
||||
break
|
||||
|
||||
if (message.parameters && message.parameters.length) {
|
||||
this.logger[messageTypeOrLevel](
|
||||
"parameters:",
|
||||
message.parameters,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,148 +1,94 @@
|
||||
import { FileLoggerOptions, LoggerOptions } from "./LoggerOptions"
|
||||
import { LogLevel, LogMessage } from "./Logger"
|
||||
import appRootPath from "app-root-path"
|
||||
import { QueryRunner } from "../query-runner/QueryRunner"
|
||||
import { Logger } from "./Logger"
|
||||
import { PlatformTools } from "../platform/PlatformTools"
|
||||
import { AbstractLogger } from "./AbstractLogger"
|
||||
|
||||
/**
|
||||
* Performs logging of the events in TypeORM.
|
||||
* This version of logger logs everything into ormlogs.log file.
|
||||
*/
|
||||
export class FileLogger implements Logger {
|
||||
export class FileLogger extends AbstractLogger {
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(
|
||||
private options?: LoggerOptions,
|
||||
options?: LoggerOptions,
|
||||
private fileLoggerOptions?: FileLoggerOptions,
|
||||
) {}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Logs query and parameters used in it.
|
||||
*/
|
||||
logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner) {
|
||||
if (
|
||||
this.options === "all" ||
|
||||
this.options === true ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("query") !== -1)
|
||||
) {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? " -- PARAMETERS: " + this.stringifyParams(parameters)
|
||||
: "")
|
||||
this.write("[QUERY]: " + sql)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs query that is failed.
|
||||
*/
|
||||
logQueryError(
|
||||
error: string,
|
||||
query: string,
|
||||
parameters?: any[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
if (
|
||||
this.options === "all" ||
|
||||
this.options === true ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("error") !== -1)
|
||||
) {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? " -- PARAMETERS: " + this.stringifyParams(parameters)
|
||||
: "")
|
||||
this.write([`[FAILED QUERY]: ${sql}`, `[QUERY ERROR]: ${error}`])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs query that is slow.
|
||||
*/
|
||||
logQuerySlow(
|
||||
time: number,
|
||||
query: string,
|
||||
parameters?: any[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? " -- PARAMETERS: " + this.stringifyParams(parameters)
|
||||
: "")
|
||||
this.write(`[SLOW QUERY: ${time} ms]: ` + sql)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs events from the schema build process.
|
||||
*/
|
||||
logSchemaBuild(message: string, queryRunner?: QueryRunner) {
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("schema") !== -1)
|
||||
) {
|
||||
this.write(message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs events from the migrations run process.
|
||||
*/
|
||||
logMigration(message: string, queryRunner?: QueryRunner) {
|
||||
this.write(message)
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform logging using given logger, or by default to the console.
|
||||
* Log has its own level and message.
|
||||
*/
|
||||
log(
|
||||
level: "log" | "info" | "warn",
|
||||
message: any,
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
switch (level) {
|
||||
case "log":
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("log") !== -1)
|
||||
)
|
||||
this.write("[LOG]: " + message)
|
||||
break
|
||||
case "info":
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("info") !== -1)
|
||||
)
|
||||
this.write("[INFO]: " + message)
|
||||
break
|
||||
case "warn":
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("warn") !== -1)
|
||||
)
|
||||
this.write("[WARN]: " + message)
|
||||
break
|
||||
}
|
||||
super(options)
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Protected Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Write log to specific output.
|
||||
*/
|
||||
protected writeLog(
|
||||
level: LogLevel,
|
||||
logMessage: LogMessage | LogMessage[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
const messages = this.prepareLogMessages(logMessage, {
|
||||
highlightSql: false,
|
||||
addColonToPrefix: false,
|
||||
})
|
||||
|
||||
const strings: string[] = []
|
||||
|
||||
for (let message of messages) {
|
||||
switch (message.type ?? level) {
|
||||
case "log":
|
||||
strings.push(`[LOG]: ${message.message}`)
|
||||
break
|
||||
|
||||
case "schema-build":
|
||||
case "migration":
|
||||
strings.push(String(message.message))
|
||||
break
|
||||
|
||||
case "info":
|
||||
strings.push(`[INFO]: ${message.message}`)
|
||||
break
|
||||
|
||||
case "query":
|
||||
strings.push(`[QUERY]: ${message.message}`)
|
||||
break
|
||||
|
||||
case "warn":
|
||||
strings.push(`[WARN]: ${message.message}`)
|
||||
break
|
||||
|
||||
case "query-slow":
|
||||
if (message.prefix === "execution time") {
|
||||
continue
|
||||
}
|
||||
|
||||
this.write(
|
||||
`[SLOW QUERY: ${message.additionalInfo?.time} ms]: ${message.message}`,
|
||||
)
|
||||
break
|
||||
|
||||
case "error":
|
||||
case "query-error":
|
||||
if (message.prefix === "query failed") {
|
||||
strings.push(`[FAILED QUERY]: ${message.message}`)
|
||||
} else if (message.type === "query-error") {
|
||||
strings.push(`[QUERY ERROR]: ${message.message}`)
|
||||
} else {
|
||||
strings.push(`[ERROR]: ${message.message}`)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
this.write(strings)
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes given strings into the log file.
|
||||
*/
|
||||
@ -163,17 +109,4 @@ export class FileLogger implements Logger {
|
||||
strings.join("\r\n") + "\r\n",
|
||||
) // todo: use async or implement promises?
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts parameters to a string.
|
||||
* Sometimes parameters can have circular objects and therefor we are handle this case too.
|
||||
*/
|
||||
protected stringifyParams(parameters: any[]) {
|
||||
try {
|
||||
return JSON.stringify(parameters)
|
||||
} catch (error) {
|
||||
// most probably circular objects in parameters
|
||||
return parameters
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,3 +49,55 @@ export interface Logger {
|
||||
queryRunner?: QueryRunner,
|
||||
): any
|
||||
}
|
||||
|
||||
/**
|
||||
* Log level.
|
||||
*/
|
||||
export type LogLevel =
|
||||
| "query"
|
||||
| "schema"
|
||||
| "error"
|
||||
| "warn"
|
||||
| "info"
|
||||
| "log"
|
||||
| "migration"
|
||||
|
||||
/**
|
||||
* Log message.
|
||||
*/
|
||||
export type LogMessage = {
|
||||
type?: LogMessageType
|
||||
prefix?: string
|
||||
message: string | number
|
||||
format?: LogMessageFormat
|
||||
parameters?: any[]
|
||||
additionalInfo?: Record<string, any>
|
||||
}
|
||||
|
||||
/**
|
||||
* Log message format.
|
||||
*/
|
||||
export type LogMessageFormat = "sql"
|
||||
|
||||
/**
|
||||
* Log message type.
|
||||
*/
|
||||
export type LogMessageType =
|
||||
| "log"
|
||||
| "info"
|
||||
| "warn"
|
||||
| "error"
|
||||
| "query"
|
||||
| "query-error"
|
||||
| "query-slow"
|
||||
| "schema-build"
|
||||
| "migration"
|
||||
|
||||
/**
|
||||
* Options for prepare log messages
|
||||
*/
|
||||
export type PrepareLogMessagesOptions = {
|
||||
highlightSql: boolean
|
||||
appendParameterAsComment: boolean
|
||||
addColonToPrefix: boolean
|
||||
}
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { LogLevel } from "./Logger"
|
||||
|
||||
/**
|
||||
* Logging options.
|
||||
*/
|
||||
export type LoggerOptions =
|
||||
| boolean
|
||||
| "all"
|
||||
| ("query" | "schema" | "error" | "warn" | "info" | "log" | "migration")[]
|
||||
export type LoggerOptions = boolean | "all" | LogLevel[]
|
||||
|
||||
/**
|
||||
* File logging option.
|
||||
|
||||
@ -1,155 +1,59 @@
|
||||
import { LoggerOptions } from "./LoggerOptions"
|
||||
import { AbstractLogger } from "./AbstractLogger"
|
||||
import { LogLevel, LogMessage } from "./Logger"
|
||||
import { QueryRunner } from "../query-runner/QueryRunner"
|
||||
import { Logger } from "./Logger"
|
||||
|
||||
/**
|
||||
* Performs logging of the events in TypeORM.
|
||||
* This version of logger uses console to log events and does not use syntax highlighting.
|
||||
*/
|
||||
export class SimpleConsoleLogger implements Logger {
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(private options?: LoggerOptions) {}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
export class SimpleConsoleLogger extends AbstractLogger {
|
||||
/**
|
||||
* Logs query and parameters used in it.
|
||||
* Write log to specific output.
|
||||
*/
|
||||
logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner) {
|
||||
if (
|
||||
this.options === "all" ||
|
||||
this.options === true ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("query") !== -1)
|
||||
) {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? " -- PARAMETERS: " + this.stringifyParams(parameters)
|
||||
: "")
|
||||
console.log("query" + ": " + sql)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs query that is failed.
|
||||
*/
|
||||
logQueryError(
|
||||
error: string,
|
||||
query: string,
|
||||
parameters?: any[],
|
||||
protected writeLog(
|
||||
level: LogLevel,
|
||||
logMessage: LogMessage | LogMessage[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
if (
|
||||
this.options === "all" ||
|
||||
this.options === true ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("error") !== -1)
|
||||
) {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? " -- PARAMETERS: " + this.stringifyParams(parameters)
|
||||
: "")
|
||||
console.log(`query failed: ` + sql)
|
||||
console.log(`error:`, error)
|
||||
}
|
||||
}
|
||||
const messages = this.prepareLogMessages(logMessage, {
|
||||
highlightSql: false,
|
||||
})
|
||||
|
||||
/**
|
||||
* Logs query that is slow.
|
||||
*/
|
||||
logQuerySlow(
|
||||
time: number,
|
||||
query: string,
|
||||
parameters?: any[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? " -- PARAMETERS: " + this.stringifyParams(parameters)
|
||||
: "")
|
||||
console.log(`query is slow: ` + sql)
|
||||
console.log(`execution time: ` + time)
|
||||
}
|
||||
for (let message of messages) {
|
||||
switch (message.type ?? level) {
|
||||
case "log":
|
||||
case "schema-build":
|
||||
case "migration":
|
||||
console.log(message.message)
|
||||
break
|
||||
|
||||
/**
|
||||
* Logs events from the schema build process.
|
||||
*/
|
||||
logSchemaBuild(message: string, queryRunner?: QueryRunner) {
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("schema") !== -1)
|
||||
) {
|
||||
console.log(message)
|
||||
}
|
||||
}
|
||||
case "info":
|
||||
case "query":
|
||||
if (message.prefix) {
|
||||
console.info(message.prefix, message.message)
|
||||
} else {
|
||||
console.info(message.message)
|
||||
}
|
||||
break
|
||||
|
||||
/**
|
||||
* Logs events from the migrations run process.
|
||||
*/
|
||||
logMigration(message: string, queryRunner?: QueryRunner) {
|
||||
console.log(message)
|
||||
}
|
||||
case "warn":
|
||||
case "query-slow":
|
||||
if (message.prefix) {
|
||||
console.warn(message.prefix, message.message)
|
||||
} else {
|
||||
console.warn(message.message)
|
||||
}
|
||||
break
|
||||
|
||||
/**
|
||||
* Perform logging using given logger, or by default to the console.
|
||||
* Log has its own level and message.
|
||||
*/
|
||||
log(
|
||||
level: "log" | "info" | "warn",
|
||||
message: any,
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
switch (level) {
|
||||
case "log":
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("log") !== -1)
|
||||
)
|
||||
console.log(message)
|
||||
break
|
||||
case "info":
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("info") !== -1)
|
||||
)
|
||||
console.info(message)
|
||||
break
|
||||
case "warn":
|
||||
if (
|
||||
this.options === "all" ||
|
||||
(Array.isArray(this.options) &&
|
||||
this.options.indexOf("warn") !== -1)
|
||||
)
|
||||
console.warn(message)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Protected Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Converts parameters to a string.
|
||||
* Sometimes parameters can have circular objects and therefor we are handle this case too.
|
||||
*/
|
||||
protected stringifyParams(parameters: any[]) {
|
||||
try {
|
||||
return JSON.stringify(parameters)
|
||||
} catch (error) {
|
||||
// most probably circular objects in parameters
|
||||
return parameters
|
||||
case "error":
|
||||
case "query-error":
|
||||
if (message.prefix) {
|
||||
console.error(message.prefix, message.message)
|
||||
} else {
|
||||
console.error(message.message)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,6 +241,14 @@ export class PlatformTools {
|
||||
console.log(chalk.underline(message))
|
||||
}
|
||||
|
||||
static info(info: any) {
|
||||
return chalk.gray(info)
|
||||
}
|
||||
|
||||
static error(error: any) {
|
||||
return chalk.red(error)
|
||||
}
|
||||
|
||||
static warn(message: string) {
|
||||
return chalk.yellow(message)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user