UNPKG

8.86 kBJavaScriptView Raw
1/**
2 * Copyright 2013 the PM2 project authors. All rights reserved.
3 * Use of this source code is governed by a license that
4 * can be found in the LICENSE file.
5 *
6 * This file wrap target application
7 * - redirect stdin, stderr to bus + log files
8 * - rename process
9 * - pid
10 */
11
12var p = require('path');
13var cst = require('../constants');
14var Utility = require('./Utility.js');
15
16// Load all env-vars from master.
17var pm2_env = JSON.parse(process.env.pm2_env);
18for(var k in pm2_env) {
19 process.env[k] = pm2_env[k];
20}
21
22// Rename process
23process.title = process.env.PROCESS_TITLE || 'node ' + pm2_env.pm_exec_path;
24
25delete process.env.pm2_env;
26
27/**
28 * Main entrance to wrap the desired code
29 */
30(function ProcessContainer() {
31 var fs = require('fs');
32
33 require('./ProcessUtils').injectModules();
34
35 var stdFile = pm2_env.pm_log_path;
36 var outFile = pm2_env.pm_out_log_path;
37 var errFile = pm2_env.pm_err_log_path;
38 var pidFile = pm2_env.pm_pid_path;
39 var script = pm2_env.pm_exec_path;
40
41 var original_send = process.send;
42
43 if (typeof(process.env.source_map_support) != 'undefined' &&
44 process.env.source_map_support !== 'false') {
45 require('source-map-support').install();
46 }
47
48 process.send = function() {
49 if (process.connected)
50 original_send.apply(this, arguments);
51 };
52
53 //send node version
54 if (process.versions && process.versions.node) {
55 process.send({
56 'node_version': process.versions.node
57 });
58 }
59
60 if (cst.MODIFY_REQUIRE)
61 require.main.filename = pm2_env.pm_exec_path;
62
63 // Resets global paths for require()
64 require('module')._initPaths();
65
66 try {
67 fs.writeFileSync(pidFile, process.pid);
68 } catch (e) {
69 console.error(e.stack || e);
70 }
71
72 // Add args to process if args specified on start
73 if (process.env.args != null)
74 process.argv = process.argv.concat(pm2_env.args);
75
76 // stdio, including: out, err and entire (both out and err if necessary).
77 var stds = {
78 out: outFile,
79 err: errFile
80 };
81 stdFile && (stds.std = stdFile);
82
83 // uid/gid management
84 if (pm2_env.uid || pm2_env.gid) {
85 try {
86 if (pm2_env.uid)
87 process.setuid(pm2_env.uid);
88 if (process.env.gid)
89 process.setgid(pm2_env.gid);
90 } catch(e) {
91 setTimeout(function() {
92 console.error('%s on call %s', e.message, e.syscall);
93 console.error('%s is not accessible', pm2_env.uid);
94 return process.exit(1);
95 }, 100);
96 }
97 }
98
99 exec(script, stds);
100})();
101
102/**
103 * Description
104 * @method exec
105 * @param {} script
106 * @param {} stds
107 * @return
108 */
109function exec(script, stds) {
110 if (p.extname(script) == '.coffee') {
111 try {
112 require('coffee-script/register');
113 } catch (e) {
114 console.error('Failed to load CoffeeScript interpreter:', e.message || e);
115 }
116 }
117
118 if (p.extname(script) == '.ls') {
119 try {
120 require('livescript');
121 } catch (e) {
122 console.error('Failed to load LiveScript interpreter:', e.message || e);
123 }
124 }
125
126 if (p.extname(script) == '.ts' || p.extname(script) == '.tsx') {
127 try {
128 require('ts-node/register');
129 } catch (e) {
130 console.error('Failed to load Typescript interpreter:', e.message || e);
131 }
132 }
133
134 process.on('message', function (msg) {
135 if (msg.type === 'log:reload') {
136 for (var k in stds){
137 if (typeof stds[k] == 'object' && !isNaN(stds[k].fd)){
138 if (stds[k].destroy) stds[k].destroy();
139 else if (stds[k].end) stds[k].end();
140 else if (stds[k].close) stds[k].close();
141 stds[k] = stds[k]._file;
142 }
143 }
144 Utility.startLogging(stds, function (err) {
145 if (err)
146 return console.error('Failed to reload logs:', err.stack);
147 console.log('Reloading log...');
148 });
149 }
150 });
151
152 var dateFns = null;
153
154 if (pm2_env.log_date_format)
155 dateFns = require('date-fns');
156
157 Utility.startLogging(stds, function (err) {
158 if (err) {
159 process.send({
160 type : 'process:exception',
161 data : {
162 message: err.message,
163 syscall: 'ProcessContainer.startLogging'
164 }
165 });
166 throw err;
167 return;
168 }
169
170 process.stderr.write = (function(write) {
171 return function(string, encoding, cb) {
172 var log_data = null;
173
174 // Disable logs if specified
175 if (pm2_env.disable_logs === true) {
176 return cb ? cb() : false;
177 }
178
179 if (pm2_env.log_type && pm2_env.log_type === 'json') {
180 log_data = JSON.stringify({
181 message : string.toString(),
182 timestamp : pm2_env.log_date_format && dateFns ?
183 dateFns.format(Date.now(), pm2_env.log_date_format) : new Date().toISOString(),
184 type : 'err',
185 process_id : pm2_env.pm_id,
186 app_name : pm2_env.name
187 }) + '\n';
188 }
189 else if (pm2_env.log_date_format && dateFns)
190 log_data = `${dateFns.format(Date.now(), pm2_env.log_date_format)}: ${string.toString()}`;
191 else
192 log_data = string.toString();
193
194 process.send({
195 type : 'log:err',
196 data : log_data
197 });
198
199 if (Utility.checkPathIsNull(pm2_env.pm_err_log_path) &&
200 (!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path)))
201 return cb ? cb() : false;
202
203 stds.std && stds.std.write && stds.std.write(log_data, encoding);
204 stds.err && stds.err.write && stds.err.write(log_data, encoding, cb);
205 };
206 })(process.stderr.write);
207
208 process.stdout.write = (function(write) {
209 return function(string, encoding, cb) {
210 var log_data = null;
211
212 // Disable logs if specified
213 if (pm2_env.disable_logs === true) {
214 return cb ? cb() : false;
215 }
216
217 if (pm2_env.log_type && pm2_env.log_type === 'json') {
218 log_data = JSON.stringify({
219 message : string.toString(),
220 timestamp : pm2_env.log_date_format && dateFns ?
221 dateFns.format(Date.now(), pm2_env.log_date_format) : new Date().toISOString(),
222 type : 'out',
223 process_id : pm2_env.pm_id,
224 app_name : pm2_env.name
225 }) + '\n';
226 }
227 else if (pm2_env.log_date_format && dateFns)
228 log_data = `${dateFns.format(Date.now(), pm2_env.log_date_format)}: ${string.toString()}`;
229 else
230 log_data = string.toString();
231
232 process.send({
233 type : 'log:out',
234 data : log_data
235 });
236
237 if (Utility.checkPathIsNull(pm2_env.pm_out_log_path) &&
238 (!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path)))
239 return cb ? cb() : null;
240
241 stds.std && stds.std.write && stds.std.write(log_data, encoding);
242 stds.out && stds.out.write && stds.out.write(log_data, encoding, cb);
243 };
244 })(process.stdout.write);
245
246 function getUncaughtExceptionListener(listener) {
247 return function uncaughtListener(err) {
248 var error = err && err.stack ? err.stack : err;
249
250 if (listener === 'unhandledRejection') {
251 error = 'You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection:\n' + error;
252 }
253
254 logError(['std', 'err'], error);
255
256 // Notify master that an uncaughtException has been catched
257 try {
258 if (err) {
259 var errObj = {};
260
261 Object.getOwnPropertyNames(err).forEach(function(key) {
262 errObj[key] = err[key];
263 });
264 }
265
266 process.send({
267 type : 'log:err',
268 data : '\n' + error + '\n'
269 });
270 process.send({
271 type : 'process:exception',
272 data : errObj !== undefined ? errObj : {message: 'No error but ' + listener + ' was caught!'}
273 });
274 } catch(e) {
275 logError(['std', 'err'], 'Channel is already closed can\'t broadcast error:\n' + e.stack);
276 }
277
278 if (!process.listeners(listener).filter(function (listener) {
279 return listener !== uncaughtListener;
280 }).length) {
281 if (listener == 'uncaughtException') {
282 process.emit('disconnect');
283 process.exit(cst.CODE_UNCAUGHTEXCEPTION);
284 }
285 }
286 }
287 }
288
289 process.on('uncaughtException', getUncaughtExceptionListener('uncaughtException'));
290 process.on('unhandledRejection', getUncaughtExceptionListener('unhandledRejection'));
291
292 // Change dir to fix process.cwd
293 process.chdir(pm2_env.pm_cwd || process.env.PWD || p.dirname(script));
294
295 require('module')._load(script, null, true);
296
297 function logError(types, error){
298 try {
299 types.forEach(function(type){
300 stds[type] && typeof stds[type].write == 'function' && stds[type].write(error + '\n');
301 });
302 } catch(e) { }
303 }
304 });
305
306}