Skip to content

Commit 6ba1c50

Browse files
authored
feat: replace console output with structured pino logging (#48)
## Summary - replace runtime console logging with structured Pino logging - add optional custom logger support in transformer options and TypeScript types - apply the same logging pattern to tests, examples, and release script - update documentation snippets to use structured logging examples ## Validation - [x] yarn lint - [x] yarn test - [x] yarn test:cross-version - [x] yarn test:types ## Notes - includes a dedicated changeset: .changeset/pino-structured-logging.md
1 parent 9bb36cf commit 6ba1c50

34 files changed

+553
-292
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"node-es-transformer": minor
3+
---
4+
5+
Replace console logging with structured Pino logging and add optional custom logger support.

PERFORMANCE.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,17 +292,20 @@ GET /_cluster/health
292292
Track ingestion progress using events:
293293

294294
```javascript
295+
const pino = require('pino');
296+
const logger = pino({ name: 'my-app', level: process.env.LOG_LEVEL || 'info' });
297+
295298
const result = await transformer({
296299
/* options */
297300
});
298301

299302
let indexed = 0;
300303
result.events.on('indexed', count => {
301304
indexed += count;
302-
console.log(`Indexed: ${indexed}`);
305+
logger.info({ indexed }, 'Progress update');
303306
});
304307

305308
result.events.on('complete', () => {
306-
console.log(`Total: ${indexed} documents`);
309+
logger.info({ indexed }, 'Ingestion complete');
307310
});
308311
```

README.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,8 @@ When `inferMappings` is enabled, the target cluster must allow `/_text_structure
387387
- Parquet/Arrow: ignored
388388
- Default: `false`
389389
- Applies only to `fileName`/`stream` sources
390-
- **`verbose`** (boolean): Enable logging and progress bars. Default: `true`.
390+
- **`verbose`** (boolean): Enable verbose logging and progress bars when using the built-in logger. Default: `true`.
391+
- **`logger`** (object): Optional custom Pino-compatible logger. If omitted, the library creates an internal Pino logger (`name: node-es-transformer`) and uses `LOG_LEVEL` (if set) or `info`/`error` based on `verbose`.
391392

392393
### Return Value
393394

@@ -400,16 +401,19 @@ The `transformer()` function returns a Promise that resolves to an object with:
400401
- `'error'`: Error occurred
401402

402403
```javascript
404+
const pino = require('pino');
405+
const logger = pino({ name: 'my-app', level: process.env.LOG_LEVEL || 'info' });
406+
403407
const result = await transformer({
404408
/* options */
405409
});
406410

407411
result.events.on('complete', () => {
408-
console.log('Ingestion complete!');
412+
logger.info('Ingestion complete');
409413
});
410414

411415
result.events.on('error', err => {
412-
console.error('Error:', err);
416+
logger.error({ err }, 'Ingestion failed');
413417
});
414418
```
415419

@@ -447,20 +451,23 @@ See [examples/typescript-example.ts](examples/typescript-example.ts) for more ex
447451
Always handle errors when using the library:
448452

449453
```javascript
454+
const pino = require('pino');
455+
const logger = pino({ name: 'my-app', level: process.env.LOG_LEVEL || 'info' });
456+
450457
transformer({
451458
/* options */
452459
})
453-
.then(() => console.log('Success'))
454-
.catch(err => console.error('Error:', err));
460+
.then(() => logger.info('Success'))
461+
.catch(err => logger.error({ err }, 'Transformer failed'));
455462

456463
// Or with async/await
457464
try {
458465
await transformer({
459466
/* options */
460467
});
461-
console.log('Success');
468+
logger.info('Success');
462469
} catch (err) {
463-
console.error('Error:', err);
470+
logger.error({ err }, 'Transformer failed');
464471
}
465472
```
466473

RELEASE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,8 @@ npm init -y
203203
# Install latest version
204204
npm install node-es-transformer
205205

206-
# Verify version
207-
node -e "console.log(require('node-es-transformer'))"
206+
# Verify package can be required
207+
node -e "require('node-es-transformer')"
208208

209209
# Check TypeScript definitions exist
210210
ls node_modules/node-es-transformer/index.d.ts

__tests__/cross_version_reindex.test.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ const transformer = require('../dist/node-es-transformer.cjs');
1111
const { Client: Client8 } = require('es8');
1212
const { Client: Client9 } = require('es9');
1313
const { readFileSync } = require('fs');
14+
const pino = require('pino');
15+
16+
const logger = pino({
17+
name: 'node-es-transformer-test',
18+
level: process.env.LOG_LEVEL || 'info',
19+
});
1420

1521
const testIndexPrefix = 'test-cross-version-';
1622

@@ -34,8 +40,8 @@ describe('Cross-version reindexing (ES 8.x to 9.x)', () => {
3440
client8 = new Client8({ node: url8 });
3541
client9 = new Client9({ node: url9 });
3642

37-
console.log(`Testing with ES 8.x at ${url8}`);
38-
console.log(`Testing with ES 9.x at ${url9}`);
43+
logger.info({ url8 }, 'Testing with ES 8.x');
44+
logger.info({ url9 }, 'Testing with ES 9.x');
3945
});
4046

4147
afterAll(async () => {

__tests__/utils/elasticsearch.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ const { Client: Client9 } = require('es9');
22
const { Client: Client8 } = require('es8');
33
const fs = require('fs');
44
const path = require('path');
5+
const pino = require('pino');
6+
7+
const logger = pino({
8+
name: 'node-es-transformer-test',
9+
level: process.env.LOG_LEVEL || 'info',
10+
});
511

612
/**
713
* Get Elasticsearch URL from testcontainer config file or fallback to localhost
@@ -14,8 +20,8 @@ function getElasticsearchUrl() {
1420
try {
1521
const config = JSON.parse(fs.readFileSync(configFile, 'utf-8'));
1622
return config.url;
17-
} catch (error) {
18-
console.warn('Failed to read testcontainer config, falling back to localhost:', error);
23+
} catch (err) {
24+
logger.warn({ err }, 'Failed to read testcontainer config, falling back to localhost');
1925
}
2026
}
2127

examples/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,12 @@ transformer({
103103
Wrap transformer calls with try/catch or use .catch():
104104

105105
```javascript
106+
const pino = require('pino');
107+
const logger = pino({ name: 'my-app', level: process.env.LOG_LEVEL || 'info' });
108+
106109
transformer({ /* options */ })
107-
.then(() => console.log('Success!'))
108-
.catch(err => console.error('Error:', err));
110+
.then(() => logger.info('Success'))
111+
.catch(err => logger.error({ err }, 'Transformer failed'));
109112
```
110113

111114
### Progress Monitoring

examples/_logger.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const pino = require('pino');
2+
3+
const logger = pino({
4+
name: 'node-es-transformer-example',
5+
level: process.env.LOG_LEVEL || 'info',
6+
timestamp: pino.stdTimeFunctions.isoTime,
7+
serializers: {
8+
err: pino.stdSerializers.err,
9+
error: pino.stdSerializers.err,
10+
},
11+
});
12+
13+
module.exports = logger;

examples/basic-file-ingestion.js

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
/**
22
* Basic File Ingestion Example
3-
*
3+
*
44
* Demonstrates how to ingest a JSON or CSV file into Elasticsearch
55
* with custom field mappings.
66
*/
77

88
const transformer = require('node-es-transformer');
9+
const logger = require('./_logger');
910

1011
// Example 1: Ingest JSON file
1112
transformer({
@@ -14,24 +15,26 @@ transformer({
1415
mappings: {
1516
properties: {
1617
'@timestamp': {
17-
type: 'date'
18+
type: 'date',
1819
},
19-
'user_name': {
20-
type: 'keyword'
20+
user_name: {
21+
type: 'keyword',
2122
},
22-
'message': {
23-
type: 'text'
23+
message: {
24+
type: 'text',
2425
},
25-
'count': {
26-
type: 'integer'
27-
}
28-
}
29-
}
30-
}).then(() => {
31-
console.log('Ingestion complete!');
32-
}).catch(err => {
33-
console.error('Error during ingestion:', err);
34-
});
26+
count: {
27+
type: 'integer',
28+
},
29+
},
30+
},
31+
})
32+
.then(() => {
33+
logger.info('Ingestion complete');
34+
})
35+
.catch(err => {
36+
logger.error({ err }, 'Error during ingestion');
37+
});
3538

3639
// Example 2: Ingest with custom Elasticsearch connection
3740
/*

examples/cross-version-reindex.js

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,45 @@
11
/**
22
* Cross-Version Reindex Example
3-
*
3+
*
44
* Demonstrates reindexing from Elasticsearch 8.x to 9.x.
55
* The library automatically detects the ES version and uses the appropriate client.
66
*/
77

88
const transformer = require('node-es-transformer');
9+
const logger = require('./_logger');
910

1011
// Example 1: Auto-detection (recommended)
1112
transformer({
1213
sourceClientConfig: {
1314
node: 'https://es8-cluster.example.com:9200',
1415
auth: {
15-
apiKey: process.env.ES8_API_KEY
16-
}
16+
apiKey: process.env.ES8_API_KEY,
17+
},
1718
},
1819
targetClientConfig: {
1920
node: 'https://es9-cluster.example.com:9200',
2021
auth: {
21-
apiKey: process.env.ES9_API_KEY
22-
}
22+
apiKey: process.env.ES9_API_KEY,
23+
},
2324
},
2425
sourceIndexName: 'my-index-v1',
2526
targetIndexName: 'my-index-v1',
26-
27+
2728
// Optional: Transform data during migration
2829
transform(doc) {
2930
// Clean up deprecated fields, add new fields, etc.
3031
return {
3132
...doc,
32-
migrated_at: new Date().toISOString()
33+
migrated_at: new Date().toISOString(),
3334
};
34-
}
35-
}).then(() => {
36-
console.log('Cross-version reindex complete!');
37-
}).catch(err => {
38-
console.error('Error during cross-version reindex:', err);
39-
});
35+
},
36+
})
37+
.then(() => {
38+
logger.info('Cross-version reindex complete');
39+
})
40+
.catch(err => {
41+
logger.error({ err }, 'Error during cross-version reindex');
42+
});
4043

4144
// Example 2: Using pre-instantiated clients (advanced)
4245
/*

0 commit comments

Comments
 (0)