Skip to content

Commit f95f3c3

Browse files
authored
Merge pull request #380 from lutovich/1.7-logging
Support configurable logging
2 parents 55d4a45 + 0a86183 commit f95f3c3

16 files changed

+594
-62
lines changed

src/v1/driver.js

+34-14
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {DirectConnectionProvider} from './internal/connection-providers';
2626
import Bookmark from './internal/bookmark';
2727
import ConnectivityVerifier from './internal/connectivity-verifier';
2828
import PoolConfig, {DEFAULT_ACQUISITION_TIMEOUT, DEFAULT_MAX_SIZE} from './internal/pool-config';
29+
import Logger from './internal/logger';
2930

3031
const DEFAULT_MAX_CONNECTION_LIFETIME = 60 * 60 * 1000; // 1 hour
3132

@@ -43,6 +44,8 @@ const READ = 'READ';
4344
*/
4445
const WRITE = 'WRITE';
4546

47+
let idGenerator = 0;
48+
4649
/**
4750
* A driver maintains one or more {@link Session}s with a remote
4851
* Neo4j instance. Through the {@link Session}s you can send statements
@@ -66,17 +69,19 @@ class Driver {
6669
constructor(hostPort, userAgent, token = {}, config = {}) {
6770
sanitizeConfig(config);
6871

72+
this._id = idGenerator++;
6973
this._hostPort = hostPort;
7074
this._userAgent = userAgent;
71-
this._openSessions = {};
72-
this._sessionIdGenerator = 0;
75+
this._openConnections = {};
7376
this._token = token;
7477
this._config = config;
78+
this._log = Logger.create(config);
7579
this._pool = new Pool(
7680
this._createConnection.bind(this),
7781
this._destroyConnection.bind(this),
7882
this._validateConnection.bind(this),
79-
PoolConfig.fromDriverConfig(config)
83+
PoolConfig.fromDriverConfig(config),
84+
this._log
8085
);
8186

8287
/**
@@ -87,6 +92,15 @@ class Driver {
8792
this._connectionProvider = null;
8893

8994
this._onCompleted = null;
95+
96+
this._afterConstruction();
97+
}
98+
99+
/**
100+
* @protected
101+
*/
102+
_afterConstruction() {
103+
this._log.info(`Direct driver ${this._id} created for server address ${this._hostPort}`);
90104
}
91105

92106
/**
@@ -118,14 +132,12 @@ class Driver {
118132
* @access private
119133
*/
120134
_createConnection(hostPort, release) {
121-
let sessionId = this._sessionIdGenerator++;
122-
let conn = connect(hostPort, this._config, this._connectionErrorCode());
135+
let conn = connect(hostPort, this._config, this._connectionErrorCode(), this._log);
123136
let streamObserver = new _ConnectionStreamObserver(this, conn);
124137
conn.initialize(this._userAgent, this._token, streamObserver);
125-
conn._id = sessionId;
126138
conn._release = () => release(hostPort, conn);
127139

128-
this._openSessions[sessionId] = conn;
140+
this._openConnections[conn.id] = conn;
129141
return conn;
130142
}
131143

@@ -145,12 +157,12 @@ class Driver {
145157
}
146158

147159
/**
148-
* Dispose of a live session, closing any associated resources.
149-
* @return {Session} new session.
160+
* Dispose of a connection.
161+
* @return {Connection} the connection to dispose.
150162
* @access private
151163
*/
152164
_destroyConnection(conn) {
153-
delete this._openSessions[conn._id];
165+
delete this._openConnections[conn.id];
154166
conn.close();
155167
}
156168

@@ -224,11 +236,19 @@ class Driver {
224236
* @return undefined
225237
*/
226238
close() {
227-
for (let sessionId in this._openSessions) {
228-
if (this._openSessions.hasOwnProperty(sessionId)) {
229-
this._openSessions[sessionId].close();
230-
}
239+
this._log.info(`Driver ${this._id} closing`);
240+
241+
try {
242+
// purge all idle connections in the connection pool
231243
this._pool.purgeAll();
244+
} finally {
245+
// then close all connections driver has ever created
246+
// it is needed to close connections that are active right now and are acquired from the pool
247+
for (let connectionId in this._openConnections) {
248+
if (this._openConnections.hasOwnProperty(connectionId)) {
249+
this._openConnections[connectionId].close();
250+
}
251+
}
232252
}
233253
}
234254
}

src/v1/index.js

+32
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@ const auth = {
6868
};
6969
const USER_AGENT = "neo4j-javascript/" + VERSION;
7070

71+
/**
72+
* Object containing predefined logging configurations. These are expected to be used as values of the driver config's <code>logging</code> property.
73+
* @property {function(level: ?string): object} console the function to create a logging config that prints all messages to <code>console.log</code> with
74+
* timestamp, level and message. It takes an optional <code>level</code> parameter which represents the maximum log level to be logged. Default value is 'info'.
75+
*/
76+
const logging = {
77+
console: level => {
78+
return {
79+
level: level,
80+
logger: (level, message) => console.log(`${global.Date.now()} ${level.toUpperCase()} ${message}`)
81+
};
82+
}
83+
};
84+
7185
/**
7286
* Construct a new Neo4j Driver. This is your main entry point for this
7387
* library.
@@ -172,6 +186,22 @@ const USER_AGENT = "neo4j-javascript/" + VERSION;
172186
* // Default value for this option is <code>false</code> because native JavaScript numbers might result
173187
* // in loss of precision in the general case.
174188
* disableLosslessIntegers: false,
189+
*
190+
* // Specify the logging configuration for the driver. Object should have two properties <code>level</code> and <code>logger</code>.
191+
* //
192+
* // Property <code>level</code> represents the logging level which should be one of: 'error', 'warn', 'info' or 'debug'. This property is optional and
193+
* // its default value is 'info'. Levels have priorities: 'error': 0, 'warn': 1, 'info': 2, 'debug': 3. Enabling a certain level also enables all
194+
* // levels with lower priority. For example: 'error', 'warn' and 'info' will be logged when 'info' level is configured.
195+
* //
196+
* // Property <code>logger</code> represents the logging function which will be invoked for every log call with an acceptable level. The function should
197+
* // take two string arguments <code>level</code> and <code>message</code>. The function should not execute any blocking or long-running operations
198+
* // because it is often executed on a hot path.
199+
* //
200+
* // No logging is done by default. See <code>neo4j.logging</code> object that contains predefined logging implementations.
201+
* logging: {
202+
* level: 'info',
203+
* logger: (level, message) => console.log(level + ' ' + message)
204+
* },
175205
* }
176206
*
177207
* @param {string} url The URL for the Neo4j database, for instance "bolt://localhost"
@@ -280,6 +310,7 @@ const forExport = {
280310
integer,
281311
Neo4jError,
282312
auth,
313+
logging,
283314
types,
284315
session,
285316
error,
@@ -301,6 +332,7 @@ export {
301332
integer,
302333
Neo4jError,
303334
auth,
335+
logging,
304336
types,
305337
session,
306338
error,

src/v1/internal/ch-node.js

-1
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,6 @@ class NodeChannel {
369369
if( this._pending !== null ) {
370370
this._pending.push( buffer );
371371
} else if( buffer instanceof NodeBuffer ) {
372-
// console.log( "[Conn#"+this.id+"] SEND: ", buffer.toString() );
373372
this._conn.write( buffer._buffer );
374373
} else {
375374
throw newError( "Don't know how to write: " + buffer );

src/v1/internal/connection-providers.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export class DirectConnectionProvider extends ConnectionProvider {
6060

6161
export class LoadBalancer extends ConnectionProvider {
6262

63-
constructor(hostPort, routingContext, connectionPool, loadBalancingStrategy, driverOnErrorCallback) {
63+
constructor(hostPort, routingContext, connectionPool, loadBalancingStrategy, driverOnErrorCallback, log) {
6464
super();
6565
this._seedRouter = hostPort;
6666
this._routingTable = new RoutingTable([this._seedRouter]);
@@ -69,6 +69,7 @@ export class LoadBalancer extends ConnectionProvider {
6969
this._driverOnErrorCallback = driverOnErrorCallback;
7070
this._hostNameResolver = LoadBalancer._createHostNameResolver();
7171
this._loadBalancingStrategy = loadBalancingStrategy;
72+
this._log = log;
7273
this._useSeedRouter = false;
7374
}
7475

@@ -111,6 +112,7 @@ export class LoadBalancer extends ConnectionProvider {
111112
if (!currentRoutingTable.isStaleFor(accessMode)) {
112113
return Promise.resolve(currentRoutingTable);
113114
}
115+
this._log.info(`Routing table is stale for ${accessMode}: ${currentRoutingTable}`);
114116
return this._refreshRoutingTable(currentRoutingTable);
115117
}
116118

@@ -235,6 +237,7 @@ export class LoadBalancer extends ConnectionProvider {
235237

236238
// make this driver instance aware of the new table
237239
this._routingTable = newRoutingTable;
240+
this._log.info(`Updated routing table ${newRoutingTable}`);
238241
}
239242

240243
static _forgetRouter(routingTable, routersArray, routerIndex) {

0 commit comments

Comments
 (0)