1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | var extend = require('xtend');
|
22 | var EventEmitter = require('events').EventEmitter;
|
23 | var inherits = require('inherits');
|
24 | var collectParallel = require('collect-parallel/object');
|
25 |
|
26 | var parallelWrite = require('./lib/parallel-write.js');
|
27 | var defaultLevels = require('./default-levels.js');
|
28 | var serializableErrorTransform =
|
29 | require('./transforms/serialize-error.js');
|
30 | var safeSerializeMeta =
|
31 | require('./transforms/safe-serialize-meta.js');
|
32 | var writePidAndHost = require('./transforms/pid-and-host.js');
|
33 | var errors = require('./errors.js');
|
34 | var makeLogMethod = require('./log-method');
|
35 | var ChildLogger = require('./child-logger');
|
36 |
|
37 | function Logger(opts) {
|
38 | if (!(this instanceof Logger)) {
|
39 | return new Logger(opts);
|
40 | }
|
41 | var self = this;
|
42 |
|
43 | if (!opts) {
|
44 | throw errors.OptsRequired();
|
45 | }
|
46 |
|
47 | if (!opts.meta) {
|
48 | throw errors.MetaRequired();
|
49 | }
|
50 |
|
51 | if (!opts.backends) {
|
52 | throw errors.BackendsRequired();
|
53 | }
|
54 |
|
55 | EventEmitter.call(this);
|
56 |
|
57 | var meta = this.meta = opts.meta;
|
58 | var transforms = opts.transforms || [];
|
59 | var basemetaTransforms = opts.basemetaTransforms || [];
|
60 |
|
61 | basemetaTransforms.forEach(function initTransforms(transform) {
|
62 | transforms.push(transform(meta));
|
63 | });
|
64 |
|
65 | transforms.push(safeSerializeMeta);
|
66 | transforms.push(serializableErrorTransform);
|
67 | transforms.push(writePidAndHost(meta));
|
68 |
|
69 | this.statsd = opts.statsd;
|
70 |
|
71 | this.path = opts.path = "";
|
72 |
|
73 |
|
74 |
|
75 | var levels = this.levels = {};
|
76 | var configuredLevels = extend(defaultLevels, opts.levels || {});
|
77 | Object.keys(configuredLevels)
|
78 | .forEach(function copyDefaultLevel(levelName) {
|
79 |
|
80 | if (!configuredLevels[levelName]) {
|
81 | return;
|
82 | }
|
83 |
|
84 |
|
85 | var level = extend({transforms: []}, configuredLevels[levelName]);
|
86 | level.transforms = level.transforms.concat(transforms);
|
87 | levels[levelName] = level;
|
88 | });
|
89 |
|
90 |
|
91 |
|
92 | Object.keys(levels)
|
93 | .forEach(function makeMethodForLevel(levelName) {
|
94 | self[levelName] = makeLogMethod(levelName);
|
95 | });
|
96 |
|
97 |
|
98 |
|
99 |
|
100 | var streams = this.streams = Object.keys(opts.backends)
|
101 | .reduce(function accumulateStreams(streamByBackend, backendName) {
|
102 | var backend = opts.backends[backendName];
|
103 | if (!backend) {
|
104 | return streamByBackend;
|
105 | }
|
106 |
|
107 | streamByBackend[backendName] = backend.createStream(meta, {
|
108 | highWaterMark: opts.highWaterMark || 1000
|
109 | });
|
110 | return streamByBackend;
|
111 | }, {});
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 | this._streamsByLevel = Object.keys(levels)
|
120 | .reduce(function accumulateStreamsByLevel(streamsByLevel, levelName) {
|
121 | if (!levels[levelName]) {
|
122 | return streamsByLevel;
|
123 | }
|
124 |
|
125 | var level = levels[levelName];
|
126 |
|
127 | streamsByLevel[levelName] = level.backends
|
128 | .reduce(function accumulateStreamsByBackend(
|
129 | levelStreams,
|
130 | backendName
|
131 | ) {
|
132 | if (streams[backendName]) {
|
133 | levelStreams.push({
|
134 | name: backendName,
|
135 | stream: streams[backendName]
|
136 | });
|
137 | }
|
138 | return levelStreams;
|
139 | }, []);
|
140 |
|
141 | return streamsByLevel;
|
142 | }, {});
|
143 | }
|
144 |
|
145 | inherits(Logger, EventEmitter);
|
146 |
|
147 | Logger.prototype.instrument = function instrument() { };
|
148 |
|
149 | Logger.prototype.close = function close(callback) {
|
150 | collectParallel(this.streams, closeEachStream, finish);
|
151 |
|
152 | function closeEachStream(stream, i, done) {
|
153 | if (stream && stream.close) {
|
154 | stream.close(done);
|
155 | }
|
156 | }
|
157 |
|
158 | function finish(err, results) {
|
159 | for (var i = 0; i < results; i++) {
|
160 | if (results[i].err) {
|
161 | callback(results[i].err);
|
162 | return;
|
163 | }
|
164 | }
|
165 | callback(null);
|
166 | }
|
167 | };
|
168 |
|
169 | Logger.prototype.destroy = function destroy() {
|
170 | Object.keys(this.streams).forEach(function destroyStreamForLevel(name) {
|
171 | var stream = this.streams[name];
|
172 | if (stream && stream.destroy) {
|
173 | stream.destroy();
|
174 | }
|
175 | }, this);
|
176 | };
|
177 |
|
178 | Logger.prototype.writeEntry = function writeEntry(entry, callback) {
|
179 | var levelName = entry.level;
|
180 | var level = this.levels[levelName];
|
181 | var logStreams = this._streamsByLevel[levelName];
|
182 | var logger = this;
|
183 | if (this.statsd && typeof this.statsd.increment === 'function') {
|
184 | this.statsd.increment('logtron.logged.' + levelName);
|
185 | }
|
186 |
|
187 | for (var i=0; i<level.transforms.length; ++i) {
|
188 | entry = level.transforms[i](entry);
|
189 | }
|
190 |
|
191 | parallelWrite(logStreams, entry, function (err) {
|
192 | if (!err) {
|
193 | if (callback) {
|
194 | callback(null);
|
195 | }
|
196 | return;
|
197 | }
|
198 |
|
199 | if (callback && typeof callback === 'function') {
|
200 | return callback(err);
|
201 | }
|
202 |
|
203 | logger.emit('error', err);
|
204 | });
|
205 | };
|
206 |
|
207 | Logger.prototype.createChild = function createChild(path, levels, opts) {
|
208 | opts = opts || {};
|
209 |
|
210 | return new ChildLogger({
|
211 | mainLogger: this,
|
212 | path: path,
|
213 | levels: levels,
|
214 | extendMeta: opts.extendMeta,
|
215 | meta: opts.meta,
|
216 | strict: opts.strict,
|
217 | metaFilter: opts.metaFilter
|
218 | });
|
219 | };
|
220 |
|
221 | module.exports = Logger;
|