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:
Christian Forgács 2023-02-07 13:34:37 +01:00 committed by GitHub
parent 9bd3a641cc
commit 12fdd73e25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 706 additions and 510 deletions

View File

@ -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

View File

@ -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"

View 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
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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,
)
}
}
}
}
}

View File

@ -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
}
}
}

View File

@ -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
}

View File

@ -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.

View File

@ -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
}
}
}
}

View File

@ -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)
}