UNPKG

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