mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
feat: add FormattedConsoleLogger (#11401)
* fix: Build ESM migrations for JS Including jsdoc for typehinting Add esm as an option in the migrate cli Update the documentation for the JS migrations Closes: #10801 * fix: Fix the migration documentation * Cleanup the types in the migrations * Add the formatted sql console * Add the formatSql to the logger * Update src/logger/FormattedConsoleLogger.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Make names in test more consistent * Add a sub query example * Set the language to the sql formatter * Import SqlLanguage as a type from sql-formatter * Remove empty console log * Remove console log * Add the dataSourceType * Remove js extension from import * Use another package to format the SQL in the logging Same package as we use to generate the migrations * Not need to add all the spaces in the log * Fix the expected formatted queries --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
fe71a0c3e4
commit
4c8fc3a7cb
@ -56,7 +56,7 @@ Different RDBMS-es have their own specific options.
|
||||
You can also specify different types of logging to be enabled, for example `["query", "error", "schema"]`.
|
||||
Learn more about [Logging](logging.md).
|
||||
|
||||
- `logger` - Logger to be used for logging purposes. Possible values are "advanced-console", "simple-console" and "file".
|
||||
- `logger` - Logger to be used for logging purposes. Possible values are "advanced-console", "formatted-console", "simple-console" and "file".
|
||||
Default is "advanced-console". You can also specify a logger class that implements `Logger` interface.
|
||||
Learn more about [Logging](logging.md).
|
||||
|
||||
|
||||
@ -89,6 +89,8 @@ TypeORM ships with 4 different types of logger:
|
||||
and sql syntax highlighting.
|
||||
- `simple-console` - this is a simple console logger which is exactly the same as the advanced logger, but it does not use any color highlighting.
|
||||
This logger can be used if you have problems / or don't like colorized logs.
|
||||
- `formatted-console` - this is almost the same as the advanced logger, but it formats sql queries to
|
||||
be more readable (using [@sqltools/formatter](https://github.com/mtxr/vscode-sqltools)).
|
||||
- `file` - this logger writes all logs into `ormlogs.log` in the root folder of your project (near `package.json`).
|
||||
- `debug` - this logger uses [debug package](https://github.com/visionmedia/debug), to turn on logging set your env variable `DEBUG=typeorm:*` (note logging option has no effect on this logger).
|
||||
|
||||
@ -131,7 +133,7 @@ export class MyCustomLogger extends AbstractLogger {
|
||||
) {
|
||||
const messages = this.prepareLogMessages(logMessage, {
|
||||
highlightSql: false,
|
||||
})
|
||||
}, queryRunner)
|
||||
|
||||
for (let message of messages) {
|
||||
switch (message.type ?? level) {
|
||||
|
||||
@ -77,6 +77,7 @@ export interface BaseDataSourceOptions {
|
||||
readonly logger?:
|
||||
| "advanced-console"
|
||||
| "simple-console"
|
||||
| "formatted-console"
|
||||
| "file"
|
||||
| "debug"
|
||||
| Logger
|
||||
|
||||
@ -103,6 +103,7 @@ export * from "./logger/AbstractLogger"
|
||||
export * from "./logger/Logger"
|
||||
export * from "./logger/LoggerOptions"
|
||||
export * from "./logger/AdvancedConsoleLogger"
|
||||
export * from "./logger/FormattedConsoleLogger"
|
||||
export * from "./logger/SimpleConsoleLogger"
|
||||
export * from "./logger/FileLogger"
|
||||
export * from "./metadata/EntityMetadata"
|
||||
|
||||
@ -293,12 +293,14 @@ export abstract class AbstractLogger implements Logger {
|
||||
| number
|
||||
| (LogMessage | string | number)[],
|
||||
options?: Partial<PrepareLogMessagesOptions>,
|
||||
queryRunner?: QueryRunner,
|
||||
): LogMessage[] {
|
||||
options = {
|
||||
...{
|
||||
addColonToPrefix: true,
|
||||
appendParameterAsComment: true,
|
||||
highlightSql: true,
|
||||
formatSql: false,
|
||||
},
|
||||
...options,
|
||||
}
|
||||
@ -314,6 +316,13 @@ export abstract class AbstractLogger implements Logger {
|
||||
if (message.format === "sql") {
|
||||
let sql = String(message.message)
|
||||
|
||||
if (options.formatSql) {
|
||||
sql = PlatformTools.formatSql(
|
||||
sql,
|
||||
queryRunner?.connection?.options.type,
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
options.appendParameterAsComment &&
|
||||
message.parameters &&
|
||||
|
||||
72
src/logger/FormattedConsoleLogger.ts
Normal file
72
src/logger/FormattedConsoleLogger.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { PlatformTools } from "../platform/PlatformTools"
|
||||
import { AbstractLogger } from "./AbstractLogger"
|
||||
import { LogLevel, LogMessage } from "./Logger"
|
||||
import { QueryRunner } from "../query-runner/QueryRunner"
|
||||
|
||||
/**
|
||||
* Performs logging of the events in TypeORM.
|
||||
* This version of logger uses console to log events, syntax highlighting and formatting.
|
||||
*/
|
||||
export class FormattedConsoleLogger extends AbstractLogger {
|
||||
/**
|
||||
* Write log to specific output.
|
||||
*/
|
||||
protected writeLog(
|
||||
level: LogLevel,
|
||||
logMessage: LogMessage | LogMessage[],
|
||||
queryRunner?: QueryRunner,
|
||||
) {
|
||||
const messages = this.prepareLogMessages(
|
||||
logMessage,
|
||||
{
|
||||
highlightSql: true,
|
||||
formatSql: true,
|
||||
},
|
||||
queryRunner,
|
||||
)
|
||||
|
||||
for (let message of messages) {
|
||||
switch (message.type ?? level) {
|
||||
case "log":
|
||||
case "schema-build":
|
||||
case "migration":
|
||||
PlatformTools.log(String(message.message))
|
||||
break
|
||||
|
||||
case "info":
|
||||
case "query":
|
||||
if (message.prefix) {
|
||||
PlatformTools.logInfo(message.prefix, message.message)
|
||||
} else {
|
||||
PlatformTools.log(String(message.message))
|
||||
}
|
||||
break
|
||||
|
||||
case "warn":
|
||||
case "query-slow":
|
||||
if (message.prefix) {
|
||||
PlatformTools.logWarn(message.prefix, message.message)
|
||||
} else {
|
||||
console.warn(
|
||||
PlatformTools.warn(String(message.message)),
|
||||
)
|
||||
}
|
||||
break
|
||||
|
||||
case "error":
|
||||
case "query-error":
|
||||
if (message.prefix) {
|
||||
PlatformTools.logError(
|
||||
message.prefix,
|
||||
String(message.message),
|
||||
)
|
||||
} else {
|
||||
console.error(
|
||||
PlatformTools.error(String(message.message)),
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -98,6 +98,7 @@ export type LogMessageType =
|
||||
*/
|
||||
export type PrepareLogMessagesOptions = {
|
||||
highlightSql: boolean
|
||||
formatSql: boolean
|
||||
appendParameterAsComment: boolean
|
||||
addColonToPrefix: boolean
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import { AdvancedConsoleLogger } from "./AdvancedConsoleLogger"
|
||||
import { FileLogger } from "./FileLogger"
|
||||
import { DebugLogger } from "./DebugLogger"
|
||||
import { ObjectUtils } from "../util/ObjectUtils"
|
||||
import { FormattedConsoleLogger } from "./FormattedConsoleLogger"
|
||||
|
||||
/**
|
||||
* Helps to create logger instances.
|
||||
@ -17,6 +18,7 @@ export class LoggerFactory {
|
||||
logger?:
|
||||
| "advanced-console"
|
||||
| "simple-console"
|
||||
| "formatted-console"
|
||||
| "file"
|
||||
| "debug"
|
||||
| Logger,
|
||||
@ -35,6 +37,9 @@ export class LoggerFactory {
|
||||
case "advanced-console":
|
||||
return new AdvancedConsoleLogger(options)
|
||||
|
||||
case "formatted-console":
|
||||
return new FormattedConsoleLogger(options)
|
||||
|
||||
case "debug":
|
||||
return new DebugLogger()
|
||||
}
|
||||
|
||||
@ -3,6 +3,9 @@ import dotenv from "dotenv"
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
import { highlight } from "sql-highlight"
|
||||
import { format as sqlFormat } from "@sqltools/formatter"
|
||||
import { type Config as SqlFormatterConfig } from "@sqltools/formatter/lib/core/types"
|
||||
import { type DatabaseType } from "../driver/types/DatabaseType"
|
||||
|
||||
export { EventEmitter } from "events"
|
||||
export { ReadStream } from "fs"
|
||||
@ -220,6 +223,27 @@ export class PlatformTools {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty-print sql string to be print in the console.
|
||||
*/
|
||||
static formatSql(sql: string, dataSourceType?: DatabaseType): string {
|
||||
const databaseLanguageMap: Record<
|
||||
string,
|
||||
SqlFormatterConfig["language"]
|
||||
> = {
|
||||
oracle: "pl/sql",
|
||||
}
|
||||
|
||||
const databaseLanguage = dataSourceType
|
||||
? databaseLanguageMap[dataSourceType] || "sql"
|
||||
: "sql"
|
||||
|
||||
return sqlFormat(sql, {
|
||||
language: databaseLanguage,
|
||||
indent: " ",
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Logging functions needed by AdvancedConsoleLogger
|
||||
*/
|
||||
|
||||
28
test/github-issues/1738/issue-1738.ts
Normal file
28
test/github-issues/1738/issue-1738.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import sinon from "sinon"
|
||||
import { PlatformTools } from "../../../src/platform/PlatformTools"
|
||||
import { FormattedConsoleLogger } from "../../../src"
|
||||
import { FORMAT_SQL_TEST_CASES } from "./queries"
|
||||
|
||||
describe("github issues > #1738 Add FormattedConsoleLogger", () => {
|
||||
let logger: FormattedConsoleLogger
|
||||
let logInfoStub: sinon.SinonStub
|
||||
let highlightStub: sinon.SinonStub
|
||||
|
||||
beforeEach(() => {
|
||||
logInfoStub = sinon.stub(PlatformTools, "logInfo")
|
||||
highlightStub = sinon.stub(PlatformTools, "highlightSql")
|
||||
highlightStub.callsFake((sql: string) => sql)
|
||||
logger = new FormattedConsoleLogger("all")
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
logInfoStub.restore()
|
||||
highlightStub.restore()
|
||||
})
|
||||
FORMAT_SQL_TEST_CASES.forEach((testCase) => {
|
||||
it(`formats sql query: ${testCase.unformatted}`, () => {
|
||||
logger.logQuery(testCase.unformatted)
|
||||
sinon.assert.calledWith(logInfoStub, "query:", testCase.formatted)
|
||||
})
|
||||
})
|
||||
})
|
||||
33
test/github-issues/1738/queries.ts
Normal file
33
test/github-issues/1738/queries.ts
Normal file
@ -0,0 +1,33 @@
|
||||
export const CASE_1_UNFORMATTED = `SELECT * FROM tbl`
|
||||
export const CASE_1_FORMATTED = `SELECT *
|
||||
FROM tbl`
|
||||
|
||||
export const CASE_2_UNFORMATTED = `SELECT tbl1.col1, tbl2.col2 FROM tbl1 INNER JOIN tbl2 ON tbl1.id = tbl2.id`
|
||||
export const CASE_2_FORMATTED = `SELECT tbl1.col1,
|
||||
tbl2.col2
|
||||
FROM tbl1
|
||||
INNER JOIN tbl2 ON tbl1.id = tbl2.id`
|
||||
|
||||
export const CASE_3_UNFORMATTED = `SELECT col1, (SELECT col2 FROM tbl2 WHERE tbl2.id = tbl1.id) AS sub_col FROM tbl1`
|
||||
export const CASE_3_FORMATTED = `SELECT col1,
|
||||
(
|
||||
SELECT col2
|
||||
FROM tbl2
|
||||
WHERE tbl2.id = tbl1.id
|
||||
) AS sub_col
|
||||
FROM tbl1`
|
||||
|
||||
export const FORMAT_SQL_TEST_CASES = [
|
||||
{
|
||||
unformatted: CASE_1_UNFORMATTED,
|
||||
formatted: CASE_1_FORMATTED,
|
||||
},
|
||||
{
|
||||
unformatted: CASE_2_UNFORMATTED,
|
||||
formatted: CASE_2_FORMATTED,
|
||||
},
|
||||
{
|
||||
unformatted: CASE_3_UNFORMATTED,
|
||||
formatted: CASE_3_FORMATTED,
|
||||
},
|
||||
]
|
||||
@ -154,6 +154,7 @@ export interface TestingOptions {
|
||||
createLogger?: () =>
|
||||
| "advanced-console"
|
||||
| "simple-console"
|
||||
| "formatted-console"
|
||||
| "file"
|
||||
| "debug"
|
||||
| Logger
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user