Skip to content
This repository was archived by the owner on Jan 12, 2023. It is now read-only.

Commit 8a3beb4

Browse files
authored
Add logstash transport support
1 parent 0e3224a commit 8a3beb4

5 files changed

+115
-22
lines changed

package-lock.json

+17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"dependencies": {
2525
"moment": "^2.24.0",
2626
"winston": "^3.2.1",
27+
"winston-logstash-transport": "^2.0.0",
2728
"winston-sentry-raven-transport": "^1.0.2"
2829
},
2930
"devDependencies": {

src/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import * as winston from 'winston';
22
import WinstonSentryRavenTransport from 'winston-sentry-raven-transport';
3-
import {loggerFactoryGenerator} from './logger-factory-generator';
3+
import { LogstashTransport } from 'winston-logstash-transport';
4+
import { loggerFactoryGenerator } from './logger-factory-generator';
45

56
export const loggerFactory = loggerFactoryGenerator({
67
winston,
78
consoleTransportClass: winston.transports.Console,
89
sentryTransportClass: WinstonSentryRavenTransport,
10+
logstashTransportClass: LogstashTransport,
911
});

src/logger-factory-generator.test.ts

+64-20
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ class FakeConsoleTransport extends TransportStream {
1717
}
1818
}
1919

20+
let lastLogstashLog;
21+
class FakeLogstashTransport extends TransportStream {
22+
log(info) {
23+
lastLogstashLog = info;
24+
}
25+
}
26+
2027
let logger;
2128
const symbolMessage= Symbol.for('message');
2229
const symbolLevel= Symbol.for('level');
@@ -25,58 +32,95 @@ describe('gupy-logger', () => {
2532
beforeEach(()=>{
2633
lastConsoleLog = null;
2734
lastSentryLog = null;
35+
lastLogstashLog = null;
36+
const loggerFactory = loggerFactoryGenerator({
37+
winston,
38+
consoleTransportClass: FakeConsoleTransport,
39+
sentryTransportClass: FakeSentryTransport,
40+
logstashTransportClass: FakeLogstashTransport,
41+
});
42+
logger = loggerFactory({
43+
config: {sentry: {enabled: true, dsn: 'any', level: 'info'},
44+
logstash: {enabled: true, host: 'logstashhost', port: 12345, level: 'info'}}
45+
});
46+
});
47+
48+
it('should init without logstash by default', () => {
2849
const loggerFactory = loggerFactoryGenerator({
2950
winston,
3051
consoleTransportClass: FakeConsoleTransport,
31-
sentryTransportClass: FakeSentryTransport
52+
sentryTransportClass: FakeSentryTransport,
53+
logstashTransportClass: undefined,
3254
});
55+
3356
logger = loggerFactory({
34-
config: {sentry: {enabled: true, dsn: 'any', level: 'info'}}
57+
config: {sentry: {enabled: true, dsn: 'any', level: 'info'}},
3558
});
59+
60+
expect(logger).be.not.equal(undefined);
3661
});
3762

3863
it('should log debug nowhere', () => {
3964
logger.debug('any info');
4065
expect(lastSentryLog).to.equal(null);
4166
expect(lastConsoleLog).to.deep.equal(null);
4267
expect(lastSentryLog).to.deep.equal(null);
68+
expect(lastLogstashLog).to.deep.equal(null);
4369
});
4470

45-
it('should log info only at console', () => {
46-
logger.info('any info');
47-
expect(lastSentryLog).to.equal(null);
48-
expect(lastConsoleLog).to.deep.equal({
71+
it('should log info only at console and logstash', () => {
72+
const expectedLog = {
4973
level: 'info',
5074
message: 'any info'
51-
});
75+
};
76+
77+
logger.info('any info');
78+
79+
expect(lastSentryLog).to.equal(null);
80+
expect(lastConsoleLog).to.deep.equal(expectedLog);
81+
expect(lastLogstashLog.application).to.equal('gupy');
82+
expect(lastLogstashLog.message).to.equal('any info');
83+
expect(lastLogstashLog.level).to.equal('info');
84+
5285
expect(lastConsoleLog[symbolMessage]).to.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2} \+\d{2}:\d{2} \[info]: any info/);
5386
expect(lastConsoleLog[symbolLevel]).to.equal('info');
5487
});
5588

56-
it('should log warn only at console', () => {
57-
logger.warn('any warn');
58-
expect(lastSentryLog).to.equal(null);
59-
expect(lastConsoleLog).to.deep.equal({
89+
it('should log warn only at console and logstash', () => {
90+
const expectedLog = {
6091
level: 'warn',
6192
message: 'any warn'
62-
});
93+
};
94+
95+
logger.warn('any warn');
96+
97+
expect(lastSentryLog).to.equal(null);
98+
expect(lastConsoleLog).to.deep.equal(expectedLog);
99+
expect(lastLogstashLog.application).to.equal('gupy');
100+
expect(lastLogstashLog.message).to.equal('any warn');
101+
expect(lastLogstashLog.level).to.equal('warn');
102+
63103
expect(lastConsoleLog[symbolMessage]).to.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2} \+\d{2}:\d{2} \[warn]: any warn/);
64104
expect(lastConsoleLog[symbolLevel]).to.equal('warn');
65105
});
66106

67-
it('should log error at sentry and console', () => {
68-
logger.error('any error');
69-
expect(lastSentryLog).to.deep.equal({
107+
it('should log error at all transport classes', () => {
108+
const expectedLog = {
70109
level: 'error',
71110
message: 'any error'
72-
});
111+
};
112+
113+
logger.error('any error');
114+
115+
expect(lastLogstashLog.application).to.equal('gupy');
116+
expect(lastLogstashLog.level).to.equal('error');
117+
expect(lastLogstashLog.message).to.equal('any error');
118+
119+
expect(lastSentryLog).to.deep.equal(expectedLog);
73120
expect(lastSentryLog[symbolMessage]).to.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2} \+\d{2}:\d{2} \[error]: any error/);
74121
expect(lastSentryLog[symbolLevel]).to.equal('error');
75122

76-
expect(lastConsoleLog).to.be.deep.equal({
77-
level: 'error',
78-
message: 'any error'
79-
});
123+
expect(lastConsoleLog).to.be.deep.equal(expectedLog);
80124
expect(lastConsoleLog[symbolMessage]).to.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2} \+\d{2}:\d{2} \[error]: any error/);
81125
expect(lastConsoleLog[symbolLevel]).to.equal('error');
82126
});

src/logger-factory-generator.ts

+30-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ declare interface IConfig {
77
dsn?: string,
88
level?: string,
99
};
10+
logstash?: {
11+
enabled?: boolean,
12+
application?: string,
13+
host?: string,
14+
port?: number,
15+
level?: string,
16+
};
1017
}
1118

1219
function prepareErrorToLog(error, messages = []) {
@@ -22,7 +29,7 @@ export interface IFactoryInterface {
2229

2330
type LoggerFactoryType = ({config}: IFactoryInterface) => Logger;
2431

25-
export const loggerFactoryGenerator = ({winston, consoleTransportClass, sentryTransportClass}): LoggerFactoryType => {
32+
export const loggerFactoryGenerator = ({winston, consoleTransportClass, sentryTransportClass, logstashTransportClass}): LoggerFactoryType => {
2633
return ({config}: IFactoryInterface) => {
2734
const transports = [];
2835
transports.push(new consoleTransportClass({
@@ -35,6 +42,28 @@ export const loggerFactoryGenerator = ({winston, consoleTransportClass, sentryTr
3542
level: 'error',
3643
}));
3744
}
45+
46+
if (config.logstash && config.logstash.enabled && logstashTransportClass) {
47+
const appendMetaInfo = winston.format((info) => {
48+
return Object.assign(info, {
49+
application: config.logstash.application || 'gupy',
50+
pid: process.pid,
51+
time: moment.utc().format('YYYY-MM-DD HH:mm Z'),
52+
});
53+
});
54+
55+
transports.push(new logstashTransportClass({
56+
host: config.logstash.host,
57+
port: config.logstash.port,
58+
level: config.logstash.level,
59+
format: winston.format.combine(
60+
appendMetaInfo(),
61+
winston.format.json(),
62+
winston.format.timestamp()
63+
),
64+
}));
65+
}
66+
3867
const logger: Logger = winston.createLogger({
3968
format: winston.format.printf(
4069
error => `${moment.utc().format('YYYY-MM-DD HH:mm Z')} [${error.level}]: ${error.message}`,

0 commit comments

Comments
 (0)