Skip to content

Commit 833ca1f

Browse files
committed
move logger to core
1 parent b5b66d9 commit 833ca1f

File tree

3 files changed

+238
-203
lines changed

3 files changed

+238
-203
lines changed

core/src/internal/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import * as connectionHolder from './connection-holder'
2626
import * as txConfig from './tx-config'
2727
import * as transactionExecutor from './transaction-executor'
2828
import * as connectivityVerifier from './connectivity-verifier'
29+
import * as logger from './logger'
2930

3031
export {
3132
util,
@@ -36,5 +37,6 @@ export {
3637
connectionHolder,
3738
txConfig,
3839
transactionExecutor,
39-
connectivityVerifier
40+
connectivityVerifier,
41+
logger
4042
}

core/src/internal/logger.ts

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
/**
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
import { newError } from '../error'
20+
21+
export type LogLevel = 'warn' | 'error' | 'info' | 'debug'
22+
type LoggerFunction = (level: LogLevel, message: string) => unknown
23+
24+
interface LoggingConfig {
25+
level?: LogLevel
26+
logger: LoggerFunction
27+
}
28+
29+
const ERROR: 'error' = 'error'
30+
const WARN: 'warn' = 'warn'
31+
const INFO: 'info' = 'info'
32+
const DEBUG: 'debug' = 'debug'
33+
34+
const DEFAULT_LEVEL = INFO
35+
36+
const levels = {
37+
[ERROR]: 0,
38+
[WARN]: 1,
39+
[INFO]: 2,
40+
[DEBUG]: 3
41+
}
42+
43+
/**
44+
* Logger used by the driver to notify about various internal events. Single logger should be used per driver.
45+
*/
46+
export class Logger {
47+
private readonly _level: LogLevel
48+
private readonly _loggerFunction: LoggerFunction
49+
/**
50+
* @constructor
51+
* @param {string} level the enabled logging level.
52+
* @param {function(level: string, message: string)} loggerFunction the function to write the log level and message.
53+
*/
54+
constructor(level: LogLevel, loggerFunction: LoggerFunction) {
55+
this._level = level
56+
this._loggerFunction = loggerFunction
57+
}
58+
59+
/**
60+
* Create a new logger based on the given driver configuration.
61+
* @param {Object} driverConfig the driver configuration as supplied by the user.
62+
* @return {Logger} a new logger instance or a no-op logger when not configured.
63+
*/
64+
static create(driverConfig: { logging?: LoggingConfig }) {
65+
if (driverConfig && driverConfig.logging) {
66+
const loggingConfig = driverConfig.logging
67+
const level = extractConfiguredLevel(loggingConfig)
68+
const loggerFunction = extractConfiguredLogger(loggingConfig)
69+
return new Logger(level, loggerFunction)
70+
}
71+
return this.noOp()
72+
}
73+
74+
/**
75+
* Create a no-op logger implementation.
76+
* @return {Logger} the no-op logger implementation.
77+
*/
78+
static noOp(): Logger {
79+
return noOpLogger
80+
}
81+
82+
/**
83+
* Check if error logging is enabled, i.e. it is not a no-op implementation.
84+
* @return {boolean} `true` when enabled, `false` otherwise.
85+
*/
86+
isErrorEnabled(): boolean {
87+
return isLevelEnabled(this._level, ERROR)
88+
}
89+
90+
/**
91+
* Log an error message.
92+
* @param {string} message the message to log.
93+
*/
94+
error(message: string) {
95+
if (this.isErrorEnabled()) {
96+
this._loggerFunction(ERROR, message)
97+
}
98+
}
99+
100+
/**
101+
* Check if warn logging is enabled, i.e. it is not a no-op implementation.
102+
* @return {boolean} `true` when enabled, `false` otherwise.
103+
*/
104+
isWarnEnabled(): boolean {
105+
return isLevelEnabled(this._level, WARN)
106+
}
107+
108+
/**
109+
* Log an warning message.
110+
* @param {string} message the message to log.
111+
*/
112+
warn(message: string) {
113+
if (this.isWarnEnabled()) {
114+
this._loggerFunction(WARN, message)
115+
}
116+
}
117+
118+
/**
119+
* Check if info logging is enabled, i.e. it is not a no-op implementation.
120+
* @return {boolean} `true` when enabled, `false` otherwise.
121+
*/
122+
isInfoEnabled(): boolean {
123+
return isLevelEnabled(this._level, INFO)
124+
}
125+
126+
/**
127+
* Log an info message.
128+
* @param {string} message the message to log.
129+
*/
130+
info(message: string) {
131+
if (this.isInfoEnabled()) {
132+
this._loggerFunction(INFO, message)
133+
}
134+
}
135+
136+
/**
137+
* Check if debug logging is enabled, i.e. it is not a no-op implementation.
138+
* @return {boolean} `true` when enabled, `false` otherwise.
139+
*/
140+
isDebugEnabled(): boolean {
141+
return isLevelEnabled(this._level, DEBUG)
142+
}
143+
144+
/**
145+
* Log a debug message.
146+
* @param {string} message the message to log.
147+
*/
148+
debug(message: string) {
149+
if (this.isDebugEnabled()) {
150+
this._loggerFunction(DEBUG, message)
151+
}
152+
}
153+
}
154+
155+
class NoOpLogger extends Logger {
156+
constructor() {
157+
super(INFO, (level: LogLevel, message: string) => {})
158+
}
159+
160+
isErrorEnabled() {
161+
return false
162+
}
163+
164+
error(message: string) {}
165+
166+
isWarnEnabled() {
167+
return false
168+
}
169+
170+
warn(message: string) {}
171+
172+
isInfoEnabled() {
173+
return false
174+
}
175+
176+
info(message: string) {}
177+
178+
isDebugEnabled() {
179+
return false
180+
}
181+
182+
debug(message: string) {}
183+
}
184+
185+
const noOpLogger = new NoOpLogger()
186+
187+
/**
188+
* Check if the given logging level is enabled.
189+
* @param {string} configuredLevel the configured level.
190+
* @param {string} targetLevel the level to check.
191+
* @return {boolean} value of `true` when enabled, `false` otherwise.
192+
*/
193+
function isLevelEnabled(configuredLevel: LogLevel, targetLevel: LogLevel) {
194+
return levels[configuredLevel] >= levels[targetLevel]
195+
}
196+
197+
/**
198+
* Extract the configured logging level from the driver's logging configuration.
199+
* @param {Object} loggingConfig the logging configuration.
200+
* @return {string} the configured log level or default when none configured.
201+
*/
202+
function extractConfiguredLevel(loggingConfig: LoggingConfig): LogLevel {
203+
if (loggingConfig && loggingConfig.level) {
204+
const configuredLevel = loggingConfig.level
205+
const value = levels[configuredLevel]
206+
if (!value && value !== 0) {
207+
throw newError(
208+
`Illegal logging level: ${configuredLevel}. Supported levels are: ${Object.keys(
209+
levels
210+
)}`
211+
)
212+
}
213+
return configuredLevel
214+
}
215+
return DEFAULT_LEVEL
216+
}
217+
218+
/**
219+
* Extract the configured logger function from the driver's logging configuration.
220+
* @param {Object} loggingConfig the logging configuration.
221+
* @return {function(level: string, message: string)} the configured logging function.
222+
*/
223+
function extractConfiguredLogger(loggingConfig: LoggingConfig): LoggerFunction {
224+
if (loggingConfig && loggingConfig.logger) {
225+
const configuredLogger = loggingConfig.logger
226+
if (configuredLogger && typeof configuredLogger === 'function') {
227+
return configuredLogger
228+
}
229+
}
230+
throw newError(`Illegal logger function: ${loggingConfig.logger}`)
231+
}

0 commit comments

Comments
 (0)