UNPKG

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