1
1
'use strict' ;
2
2
3
3
const amqplib = require ( 'amqplib' ) ;
4
+ const debug = require ( 'debug' ) ( 'log4js:rabbitmq' ) ;
4
5
5
6
function rabbitmqAppender ( config , layout ) {
6
7
const host = config . host || '127.0.0.1' ;
7
8
const port = config . port || 5672 ;
8
9
const username = config . username || 'guest' ;
9
10
const password = config . password || 'guest' ;
10
- const exchange = config . exchange || '' ;
11
- const type = config . mq_type || '' ;
11
+ const exchange = config . exchange || 'log ' ;
12
+ const type = config . mq_type || 'direct ' ;
12
13
const durable = config . durable || false ;
13
14
const routingKey = config . routing_key || 'logstash' ;
15
+ const vhost = config . vhost || '/' ;
16
+ const shutdownTimeout = config . shutdownTimeout || 10000 ;
14
17
const con = {
15
18
protocol : 'amqp' ,
16
19
hostname : host ,
@@ -20,30 +23,106 @@ function rabbitmqAppender(config, layout) {
20
23
locale : 'en_US' ,
21
24
frameMax : 0 ,
22
25
heartbeat : 0 ,
23
- vhost : '/' ,
26
+ vhost : vhost ,
24
27
routing_key : routingKey ,
25
28
exchange : exchange ,
26
29
mq_type : type ,
27
30
durable : durable ,
28
31
} ;
29
- const client = amqplib . connect ( con ) ;
30
- const publish = ( message ) => {
31
- client . then ( ( conn ) => {
32
- const rn = conn . createChannel ( ) . then ( ( ch ) => {
33
- const ok = ch . assertExchange ( exchange , type , { durable : durable } ) ;
34
- return ok . then ( ( ) => {
32
+ const messagesToSend = [ ] ;
33
+ let promisesWaiting = 0 ;
34
+ let waitingToConnect = true ;
35
+ let connection ;
36
+
37
+ debug ( 'Connecting...' ) ;
38
+ amqplib . connect ( con ) . then ( ( c ) => {
39
+ connection = c ;
40
+ waitingToConnect = false ;
41
+ debug ( 'Connected.' ) ;
42
+ } ) . catch ( ( e ) => {
43
+ debug ( 'connect failed.' ) ;
44
+ waitingToConnect = false ;
45
+ console . error ( e ) ; // eslint-disable-line
46
+ } ) ;
47
+
48
+ const send = ( messages ) => {
49
+ const rn = connection . createChannel ( ) . then ( ( ch ) => {
50
+ const ok = ch . assertExchange ( exchange , type , { durable : durable } ) ;
51
+ return ok . then ( ( ) => {
52
+ messages . forEach ( ( message ) => {
53
+ debug ( 'Sending message.' ) ;
35
54
ch . publish ( exchange , routingKey , Buffer . from ( message ) ) ;
36
- return ch . close ( ) ;
37
55
} ) ;
56
+ messages . length = 0 ;
57
+ return ch . close ( ) ;
38
58
} ) ;
39
- return rn ;
40
- } ) . catch ( e => console . error ( e ) ) ; //eslint-disable-line
59
+ } ) ;
60
+ promisesWaiting += 1 ;
61
+ debug ( `Promises waiting: ${ promisesWaiting } ` ) ;
62
+ rn . then ( ( ) => {
63
+ promisesWaiting -= 1 ;
64
+ debug ( `Promise resolved. Waiting is now: ${ promisesWaiting } ` ) ;
65
+ } ) ;
66
+ } ;
67
+
68
+ const publish = ( message ) => {
69
+ if ( message ) {
70
+ messagesToSend . push ( message ) ;
71
+ debug ( `Added message to buffer. Buffer length: ${ messagesToSend . length } ` ) ;
72
+ }
73
+ if ( ! waitingToConnect && connection ) {
74
+ debug ( 'Sending buffer.' ) ;
75
+ send ( messagesToSend ) ;
76
+ }
77
+ } ;
78
+
79
+ const waitForPromises = ( done ) => {
80
+ let howLongWaiting = 0 ;
81
+ const checker = ( ) => {
82
+ howLongWaiting += 100 ;
83
+ debug ( `waitingToConnect? ${ waitingToConnect } ` ) ;
84
+ if ( messagesToSend . length > 0 ) {
85
+ debug ( 'Messages to send.' ) ;
86
+ publish ( ) ;
87
+ }
88
+ if ( howLongWaiting > shutdownTimeout ) {
89
+ debug ( `Done waiting for promises. Waiting: ${ promisesWaiting } ` ) ;
90
+ if ( connection ) {
91
+ connection . close ( ) . then ( done ) ;
92
+ return ;
93
+ }
94
+ done ( ) ;
95
+ return ;
96
+ }
97
+ if ( ! waitingToConnect && connection ) {
98
+ if ( messagesToSend . length > 0 || promisesWaiting > 0 ) {
99
+ debug ( 'Promises to wait for.' ) ;
100
+ setTimeout ( checker , 100 ) ;
101
+ return ;
102
+ }
103
+ connection . close ( ) . then ( done ) ;
104
+ return ;
105
+ }
106
+ debug ( 'Nothing to wait for, shutdown now.' ) ;
107
+ done ( ) ;
108
+ } ;
109
+ setTimeout ( checker , 100 ) ;
41
110
} ;
42
111
43
112
const appender = loggingEvent => publish ( layout ( loggingEvent ) ) ;
44
113
45
114
appender . shutdown = function ( done ) {
46
- client . close ( ) . then ( done ) ;
115
+ debug ( 'Appender shutdown.' ) ;
116
+ debug ( `waitingToConnect: ${ waitingToConnect } ,
117
+ messagesToSend: ${ messagesToSend } ,
118
+ promisesWaiting: ${ promisesWaiting } ` ) ;
119
+ if ( promisesWaiting > 0 || messagesToSend . length > 0 ) {
120
+ debug ( `Things to do, will wait up to ${ shutdownTimeout } ms.` ) ;
121
+ waitForPromises ( done ) ;
122
+ } else {
123
+ debug ( 'Nothing to wait for, shutdown now.' ) ;
124
+ done ( ) ;
125
+ }
47
126
} ;
48
127
return appender ;
49
128
}
0 commit comments