Skip to content

Commit d0d2a0e

Browse files
committed
Log acme results to graylog
1 parent a416228 commit d0d2a0e

File tree

7 files changed

+165
-48
lines changed

7 files changed

+165
-48
lines changed

acme.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const serverOptions = {
2121
const server = restify.createServer(serverOptions);
2222

2323
// res.pipe does not work if Gzip is enabled
24-
server.use(restify.plugins.gzipResponse());
24+
//server.use(restify.plugins.gzipResponse());
2525

2626
server.use(
2727
restify.plugins.queryParser({

config/default.toml

+4
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,7 @@ url = "http://127.0.0.1:9200"
109109
user = "elastic"
110110
pass = "supersecret"
111111
index = "wildduck"
112+
113+
[elasticsearch.indexer]
114+
# idexing worker
115+
enabled = false

indexer.js

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
'use strict';
2+
3+
const log = require('npmlog');
4+
const config = require('wild-config');
5+
const Gelf = require('gelf');
6+
const os = require('os');
7+
const Queue = require('bull');
8+
9+
let loggelf;
10+
11+
module.exports.start = callback => {
12+
if (!config.elasticsearch || !config.elasticsearch.indexer || !config.elasticsearch.indexer.enabled) {
13+
return setImmediate(() => callback(null, false));
14+
}
15+
16+
const component = config.log.gelf.component || 'wildduck';
17+
const hostname = config.log.gelf.hostname || os.hostname();
18+
const gelf =
19+
config.log.gelf && config.log.gelf.enabled
20+
? new Gelf(config.log.gelf.options)
21+
: {
22+
// placeholder
23+
emit: (key, message) => log.info('Gelf', JSON.stringify(message))
24+
};
25+
26+
loggelf = message => {
27+
if (typeof message === 'string') {
28+
message = {
29+
short_message: message
30+
};
31+
}
32+
33+
message = message || {};
34+
35+
if (!message.short_message || message.short_message.indexOf(component.toUpperCase()) !== 0) {
36+
message.short_message = component.toUpperCase() + ' ' + (message.short_message || '');
37+
}
38+
39+
message.facility = component; // facility is deprecated but set by the driver if not provided
40+
message.host = hostname;
41+
message.timestamp = Date.now() / 1000;
42+
message._component = component;
43+
Object.keys(message).forEach(key => {
44+
if (!message[key]) {
45+
delete message[key];
46+
}
47+
});
48+
try {
49+
gelf.emit('gelf.log', message);
50+
} catch (err) {
51+
log.error('Gelf', err);
52+
}
53+
};
54+
55+
const indexingQueue = new Queue('indexing', typeof config.dbs.redis === 'object' ? { redis: config.dbs.redis } : config.dbs.redis);
56+
57+
indexingQueue.process(async job => {
58+
try {
59+
if (!job || !job.data || !job.data.ev) {
60+
return false;
61+
}
62+
const data = job.data;
63+
console.log('DATA FOR INDEXING', data);
64+
65+
loggelf({ _msg: 'hellow world' });
66+
} catch (err) {
67+
log.error('Indexing', err);
68+
throw err;
69+
}
70+
});
71+
72+
callback();
73+
};

lib/acme/certs.js

+29-4
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,26 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
268268
let updated = await certHandler.update({ _id: certificateData._id }, updates, { certUpdated: true });
269269
if (!updated) {
270270
log.error('ACME', 'Failed to generate certificate for %s. Update failed', domain);
271+
certHandler.loggelf({
272+
short_message: `SNI cert provisioning failed for ${domain}`,
273+
_sni_servername: domain,
274+
_cert_id: certificateData._id.toString(),
275+
_cert_action: 'provision',
276+
_cert_error: 'No response',
277+
_cert_error_code: 'NoResponse'
278+
});
271279
return cert;
272280
}
273281

274282
log.info('ACME', 'Certificate successfully generated for %s (expires %s)', domain, parsed.validTo);
283+
certHandler.loggelf({
284+
short_message: `SNI cert provisioned for ${domain}`,
285+
_sni_servername: domain,
286+
_cert_id: certificateData._id.toString(),
287+
_cert_action: 'provision',
288+
_cert_result: 'success',
289+
_cert_expires: updates.expires.toISOString()
290+
});
275291
return await certHandler.getRecord({ _id: certificateData._id }, true);
276292
} catch (err) {
277293
try {
@@ -299,11 +315,20 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
299315
} catch (err) {
300316
log.error('ACME', 'Failed to update certificate record domain=%s error=%s', domain, err.message);
301317
}
302-
}
303318

304-
if (certificateData && certificateData.cert) {
305-
// use existing certificate data if exists
306-
return certificateData;
319+
certHandler.loggelf({
320+
short_message: `SNI cert provisioning failed for ${domain}`,
321+
_sni_servername: domain,
322+
_cert_id: certificateData._id.toString(),
323+
_cert_action: 'provision',
324+
_cert_error: err.message,
325+
_cert_error_code: err.code
326+
});
327+
328+
if (certificateData && certificateData.cert) {
329+
// use existing certificate data if exists
330+
return certificateData;
331+
}
307332
}
308333

309334
throw err;

lib/elasticsearch.js

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ const init = async () => {
4444
} else if (indexInfo && indexInfo.updated && indexInfo.changes) {
4545
log.info('ElasticSearch', 'Index "%s" updated (%s)', config.elasticsearch.index, JSON.stringify(indexInfo.changes));
4646
}
47+
48+
return true;
4749
};
4850

4951
module.exports = { init };

server.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@ if (!processCount || processCount <= 1) {
6767
// single process mode, do not fork anything
6868

6969
initElasticSearch()
70-
.then(() => {
71-
log.info('App', `ElasticSearch setup checked`);
70+
.then(started => {
71+
if (started) {
72+
log.verbose('App', `ElasticSearch setup checked`);
73+
}
7274
})
7375
.catch(err => {
7476
log.error('App', `ElasticSearch setup failed: ${err.message}${err.meta?.statusCode ? ` (${err.meta?.statusCode})` : ''}`);
@@ -98,8 +100,10 @@ if (!processCount || processCount <= 1) {
98100

99101
// Fork workers.
100102
initElasticSearch()
101-
.then(() => {
102-
log.info('App', `ElasticSearch setup checked`);
103+
.then(started => {
104+
if (started) {
105+
log.verbose('App', `ElasticSearch setup checked`);
106+
}
103107
})
104108
.catch(err => {
105109
log.error('App', `ElasticSearch setup failed: ${err.message}${err.meta?.statusCode ? ` (${err.meta?.statusCode})` : ''}`);

worker.js

+48-39
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const api = require('./api');
99
const acme = require('./acme');
1010
const tasks = require('./tasks');
1111
const webhooks = require('./webhooks');
12+
const indexer = require('./indexer');
1213
const plugins = require('./lib/plugins');
1314
const db = require('./lib/db');
1415
const errors = require('./lib/errors');
@@ -38,71 +39,79 @@ db.connect(err => {
3839
return setTimeout(() => process.exit(1), 3000);
3940
}
4041

41-
// Start IMAP server
42-
imap(err => {
42+
indexer.start(err => {
4343
if (err) {
44-
log.error('App', 'Failed to start IMAP server. %s', err.message);
44+
log.error('App', 'Failed to start indexer process. %s', err.message);
4545
errors.notify(err);
4646
return setTimeout(() => process.exit(1), 3000);
4747
}
48-
// Start POP3 server
49-
pop3(err => {
48+
49+
// Start IMAP server
50+
imap(err => {
5051
if (err) {
51-
log.error('App', 'Failed to start POP3 server');
52+
log.error('App', 'Failed to start IMAP server. %s', err.message);
5253
errors.notify(err);
5354
return setTimeout(() => process.exit(1), 3000);
5455
}
55-
// Start LMTP maildrop server
56-
lmtp(err => {
56+
// Start POP3 server
57+
pop3(err => {
5758
if (err) {
58-
log.error('App', 'Failed to start LMTP server');
59+
log.error('App', 'Failed to start POP3 server');
5960
errors.notify(err);
6061
return setTimeout(() => process.exit(1), 3000);
6162
}
62-
63-
// Start HTTP API server
64-
api(err => {
63+
// Start LMTP maildrop server
64+
lmtp(err => {
6565
if (err) {
66-
log.error('App', 'Failed to start API server');
66+
log.error('App', 'Failed to start LMTP server');
6767
errors.notify(err);
6868
return setTimeout(() => process.exit(1), 3000);
6969
}
7070

71-
// Start HTTP ACME server
72-
acme(err => {
71+
// Start HTTP API server
72+
api(err => {
7373
if (err) {
74-
log.error('App', 'Failed to start ACME server');
74+
log.error('App', 'Failed to start API server');
7575
errors.notify(err);
7676
return setTimeout(() => process.exit(1), 3000);
7777
}
7878

79-
// downgrade user and group if needed
80-
if (config.group) {
81-
try {
82-
process.setgid(config.group);
83-
log.info('App', 'Changed group to "%s" (%s)', config.group, process.getgid());
84-
} catch (E) {
85-
log.error('App', 'Failed to change group to "%s" (%s)', config.group, E.message);
86-
errors.notify(E);
79+
// Start HTTP ACME server
80+
acme(err => {
81+
if (err) {
82+
log.error('App', 'Failed to start ACME server');
83+
errors.notify(err);
8784
return setTimeout(() => process.exit(1), 3000);
8885
}
89-
}
90-
if (config.user) {
91-
try {
92-
process.setuid(config.user);
93-
log.info('App', 'Changed user to "%s" (%s)', config.user, process.getuid());
94-
} catch (E) {
95-
log.error('App', 'Failed to change user to "%s" (%s)', config.user, E.message);
96-
errors.notify(E);
97-
return setTimeout(() => process.exit(1), 3000);
86+
87+
// downgrade user and group if needed
88+
if (config.group) {
89+
try {
90+
process.setgid(config.group);
91+
log.info('App', 'Changed group to "%s" (%s)', config.group, process.getgid());
92+
} catch (E) {
93+
log.error('App', 'Failed to change group to "%s" (%s)', config.group, E.message);
94+
errors.notify(E);
95+
return setTimeout(() => process.exit(1), 3000);
96+
}
97+
}
98+
if (config.user) {
99+
try {
100+
process.setuid(config.user);
101+
log.info('App', 'Changed user to "%s" (%s)', config.user, process.getuid());
102+
} catch (E) {
103+
log.error('App', 'Failed to change user to "%s" (%s)', config.user, E.message);
104+
errors.notify(E);
105+
return setTimeout(() => process.exit(1), 3000);
106+
}
98107
}
99-
}
100108

101-
plugins.init('receiver');
102-
plugins.handler.load(() => {
103-
log.verbose('Plugins', 'Plugins loaded');
104-
plugins.handler.runHooks('init', [], () => {
105-
log.info('App', 'All servers started, ready to process some mail');
109+
plugins.init('receiver');
110+
plugins.handler.load(() => {
111+
log.verbose('Plugins', 'Plugins loaded');
112+
plugins.handler.runHooks('init', [], () => {
113+
log.info('App', 'All servers started, ready to process some mail');
114+
});
106115
});
107116
});
108117
});

0 commit comments

Comments
 (0)