GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_report.cc Lines: 258 269 95.9 %
Date: 2019-02-26 22:23:30 Branches: 52 80 65.0 %

Line Branch Exec Source
1
2
#include "node_report.h"
3
#include "ares.h"
4
#include "debug_utils.h"
5
#include "http_parser.h"
6
#include "nghttp2/nghttp2ver.h"
7
#include "node_internals.h"
8
#include "node_metadata.h"
9
#include "zlib.h"
10
11
#include <atomic>
12
#include <fstream>
13
14
#ifdef _WIN32
15
#include <Lm.h>
16
#include <Windows.h>
17
#include <dbghelp.h>
18
#include <process.h>
19
#include <psapi.h>
20
#include <tchar.h>
21
#include <cwctype>
22
#else
23
#include <sys/resource.h>
24
// Get the standard printf format macros for C99 stdint types.
25
#ifndef __STDC_FORMAT_MACROS
26
#define __STDC_FORMAT_MACROS
27
#endif
28
#include <cxxabi.h>
29
#include <dlfcn.h>
30
#include <inttypes.h>
31
#endif
32
33
#include <fcntl.h>
34
#include <string.h>
35
#include <time.h>
36
#include <iomanip>
37
38
#ifndef _MSC_VER
39
#include <strings.h>
40
#endif
41
42
#ifdef __APPLE__
43
#include <mach-o/dyld.h>
44
#endif
45
46
#ifndef _WIN32
47
extern char** environ;
48
#endif
49
50
constexpr int NANOS_PER_SEC = 1000 * 1000 * 1000;
51
constexpr double SEC_PER_MICROS = 1e-6;
52
53
namespace report {
54
using node::arraysize;
55
using node::Environment;
56
using node::Mutex;
57
using node::NativeSymbolDebuggingContext;
58
using node::PerIsolateOptions;
59
using v8::HeapSpaceStatistics;
60
using v8::HeapStatistics;
61
using v8::Isolate;
62
using v8::Local;
63
using v8::Number;
64
using v8::StackTrace;
65
using v8::String;
66
using v8::V8;
67
using v8::Value;
68
69
// Internal/static function declarations
70
static void WriteNodeReport(Isolate* isolate,
71
                            Environment* env,
72
                            const char* message,
73
                            const char* location,
74
                            const std::string& filename,
75
                            std::ostream& out,
76
                            Local<String> stackstr,
77
                            TIME_TYPE* tm_struct);
78
static void PrintVersionInformation(JSONWriter* writer);
79
static void PrintJavaScriptStack(JSONWriter* writer,
80
                                 Isolate* isolate,
81
                                 Local<String> stackstr,
82
                                 const char* location);
83
static void PrintNativeStack(JSONWriter* writer);
84
#ifndef _WIN32
85
static void PrintResourceUsage(JSONWriter* writer);
86
#endif
87
static void PrintGCStatistics(JSONWriter* writer, Isolate* isolate);
88
static void PrintSystemInformation(JSONWriter* writer);
89
static void PrintLoadedLibraries(JSONWriter* writer);
90
static void PrintComponentVersions(JSONWriter* writer);
91
static void PrintRelease(JSONWriter* writer);
92
static void LocalTime(TIME_TYPE* tm_struct);
93
94
// Global variables
95
static std::atomic_int seq = {0};  // sequence number for report filenames
96
97
// External function to trigger a report, writing to file.
98
// The 'name' parameter is in/out: an input filename is used
99
// if supplied, and the actual filename is returned.
100
6
std::string TriggerNodeReport(Isolate* isolate,
101
                              Environment* env,
102
                              const char* message,
103
                              const char* location,
104
                              std::string name,
105
                              Local<String> stackstr) {
106
6
  std::ostringstream oss;
107
12
  std::string filename;
108
12
  std::shared_ptr<PerIsolateOptions> options;
109
6
  if (env != nullptr) options = env->isolate_data()->options();
110
111
  // Obtain the current time and the pid (platform dependent)
112
  TIME_TYPE tm_struct;
113
6
  LocalTime(&tm_struct);
114
  // Determine the required report filename. In order of priority:
115
  //   1) supplied on API 2) configured on startup 3) default generated
116
6
  if (!name.empty()) {
117
    // Filename was specified as API parameter, use that
118
2
    oss << name;
119

4
  } else if (env != nullptr && options->report_filename.length() > 0) {
120
    // File name was supplied via start-up option, use that
121
1
    oss << options->report_filename;
122
  } else {
123
    // Construct the report filename, with timestamp, pid and sequence number
124
3
    oss << "report";
125
#ifdef _WIN32
126
    oss << "." << std::setfill('0') << std::setw(4) << tm_struct.wYear;
127
    oss << std::setfill('0') << std::setw(2) << tm_struct.wMonth;
128
    oss << std::setfill('0') << std::setw(2) << tm_struct.wDay;
129
    oss << "." << std::setfill('0') << std::setw(2) << tm_struct.wHour;
130
    oss << std::setfill('0') << std::setw(2) << tm_struct.wMinute;
131
    oss << std::setfill('0') << std::setw(2) << tm_struct.wSecond;
132
#else  // UNIX, OSX
133
3
    oss << "." << std::setfill('0') << std::setw(4) << tm_struct.tm_year + 1900;
134
3
    oss << std::setfill('0') << std::setw(2) << tm_struct.tm_mon + 1;
135
3
    oss << std::setfill('0') << std::setw(2) << tm_struct.tm_mday;
136
3
    oss << "." << std::setfill('0') << std::setw(2) << tm_struct.tm_hour;
137
3
    oss << std::setfill('0') << std::setw(2) << tm_struct.tm_min;
138
3
    oss << std::setfill('0') << std::setw(2) << tm_struct.tm_sec;
139
#endif
140
3
    oss << "." << uv_os_getpid();
141
3
    oss << "." << std::setfill('0') << std::setw(3) << ++seq;
142
3
    oss << ".json";
143
  }
144
145
6
  filename = oss.str();
146
  // Open the report file stream for writing. Supports stdout/err,
147
  // user-specified or (default) generated name
148
12
  std::ofstream outfile;
149
  std::ostream* outstream;
150
6
  if (filename == "stdout") {
151
    outstream = &std::cout;
152
6
  } else if (filename == "stderr") {
153
    outstream = &std::cerr;
154
  } else {
155
    // Regular file. Append filename to directory path if one was specified
156

6
    if (env != nullptr && options->report_directory.length() > 0) {
157
5
      std::string pathname = options->report_directory;
158
5
      pathname += PATHSEP;
159
5
      pathname += filename;
160
5
      outfile.open(pathname, std::ios::out | std::ios::binary);
161
    } else {
162
1
      outfile.open(filename, std::ios::out | std::ios::binary);
163
    }
164
    // Check for errors on the file open
165
6
    if (!outfile.is_open()) {
166
      std::cerr << std::endl
167
                << "Failed to open Node.js report file: " << filename;
168
169
      if (env != nullptr && options->report_directory.length() > 0)
170
        std::cerr << " directory: " << options->report_directory;
171
172
      std::cerr << " (errno: " << errno << ")" << std::endl;
173
      return "";
174
    }
175
176
6
    std::cerr << std::endl
177
6
              << "Writing Node.js report to file: " << filename << std::endl;
178
  }
179
180
  // Pass our stream about by reference, not by copying it.
181
6
  std::ostream& out = outfile.is_open() ? outfile : *outstream;
182
183
  WriteNodeReport(
184
6
      isolate, env, message, location, filename, out, stackstr, &tm_struct);
185
186
  // Do not close stdout/stderr, only close files we opened.
187
6
  if (outfile.is_open()) {
188
6
    outfile.close();
189
  }
190
191
6
  std::cerr << "Node.js report completed" << std::endl;
192
12
  return filename;
193
}
194
195
// External function to trigger a report, writing to a supplied stream.
196
4
void GetNodeReport(Isolate* isolate,
197
                   Environment* env,
198
                   const char* message,
199
                   const char* location,
200
                   Local<String> stackstr,
201
                   std::ostream& out) {
202
  // Obtain the current time and the pid (platform dependent)
203
  TIME_TYPE tm_struct;
204
4
  LocalTime(&tm_struct);
205
  WriteNodeReport(
206
4
      isolate, env, message, location, "", out, stackstr, &tm_struct);
207
4
}
208
209
// Internal function to coordinate and write the various
210
// sections of the report to the supplied stream
211
10
static void WriteNodeReport(Isolate* isolate,
212
                            Environment* env,
213
                            const char* message,
214
                            const char* location,
215
                            const std::string& filename,
216
                            std::ostream& out,
217
                            Local<String> stackstr,
218
                            TIME_TYPE* tm_struct) {
219
10
  uv_pid_t pid = uv_os_getpid();
220
221
  // Save formatting for output stream.
222
10
  std::ios old_state(nullptr);
223
10
  old_state.copyfmt(out);
224
225
  // File stream opened OK, now start printing the report content:
226
  // the title and header information (event, filename, timestamp and pid)
227
228
10
  JSONWriter writer(out);
229
10
  writer.json_start();
230
10
  writer.json_objectstart("header");
231
232
10
  writer.json_keyvalue("event", message);
233
10
  writer.json_keyvalue("location", location);
234
10
  if (!filename.empty())
235
6
    writer.json_keyvalue("filename", filename);
236
  else
237
4
    writer.json_keyvalue("filename", JSONWriter::Null{});
238
239
  // Report dump event and module load date/time stamps
240
  char timebuf[64];
241
#ifdef _WIN32
242
  snprintf(timebuf,
243
           sizeof(timebuf),
244
           "%4d-%02d-%02dT%02d:%02d:%02dZ",
245
           tm_struct->wYear,
246
           tm_struct->wMonth,
247
           tm_struct->wDay,
248
           tm_struct->wHour,
249
           tm_struct->wMinute,
250
           tm_struct->wSecond);
251
  writer.json_keyvalue("dumpEventTime", timebuf);
252
#else  // UNIX, OSX
253
  snprintf(timebuf,
254
           sizeof(timebuf),
255
           "%4d-%02d-%02dT%02d:%02d:%02dZ",
256
           tm_struct->tm_year + 1900,
257
           tm_struct->tm_mon + 1,
258
           tm_struct->tm_mday,
259
           tm_struct->tm_hour,
260
           tm_struct->tm_min,
261
10
           tm_struct->tm_sec);
262
10
  writer.json_keyvalue("dumpEventTime", timebuf);
263
  struct timeval ts;
264
10
  gettimeofday(&ts, nullptr);
265
  writer.json_keyvalue("dumpEventTimeStamp",
266
10
                       std::to_string(ts.tv_sec * 1000 + ts.tv_usec / 1000));
267
#endif
268
  // Report native process ID
269
10
  writer.json_keyvalue("processId", pid);
270
271
  // Report out the command line.
272
10
  if (!node::per_process::cli_options->cmdline.empty()) {
273
10
    writer.json_arraystart("commandLine");
274
42
    for (std::string arg : node::per_process::cli_options->cmdline) {
275
32
      writer.json_element(arg);
276
32
    }
277
10
    writer.json_arrayend();
278
  }
279
280
  // Report Node.js and OS version information
281
10
  PrintVersionInformation(&writer);
282
10
  writer.json_objectend();
283
284
  // Report summary JavaScript stack backtrace
285
10
  PrintJavaScriptStack(&writer, isolate, stackstr, location);
286
287
  // Report native stack backtrace
288
10
  PrintNativeStack(&writer);
289
290
  // Report V8 Heap and Garbage Collector information
291
10
  PrintGCStatistics(&writer, isolate);
292
293
  // Report OS and current thread resource usage
294
#ifndef _WIN32
295
10
  PrintResourceUsage(&writer);
296
#endif
297
298
10
  writer.json_arraystart("libuv");
299
10
  if (env != nullptr) {
300
10
    uv_walk(env->event_loop(), WalkHandle, static_cast<void*>(&writer));
301
302
10
    writer.json_start();
303
10
    writer.json_keyvalue("type", "loop");
304
    writer.json_keyvalue("is_active",
305
10
        static_cast<bool>(uv_loop_alive(env->event_loop())));
306
    writer.json_keyvalue("address",
307
10
        ValueToHexString(reinterpret_cast<int64_t>(env->event_loop())));
308
10
    writer.json_end();
309
  }
310
311
10
  writer.json_arrayend();
312
313
  // Report operating system information
314
10
  PrintSystemInformation(&writer);
315
316
10
  writer.json_objectend();
317
318
  // Restore output stream formatting.
319
10
  out.copyfmt(old_state);
320
10
}
321
322
// Report Node.js version, OS version and machine information.
323
10
static void PrintVersionInformation(JSONWriter* writer) {
324
10
  std::ostringstream buf;
325
  // Report Node version
326
10
  buf << "v" << NODE_VERSION_STRING;
327
10
  writer->json_keyvalue("nodejsVersion", buf.str());
328
10
  buf.str("");
329
330
#ifndef _WIN32
331
  // Report compiler and runtime glibc versions where possible.
332
  const char* (*libc_version)();
333
  *(reinterpret_cast<void**>(&libc_version)) =
334
10
      dlsym(RTLD_DEFAULT, "gnu_get_libc_version");
335
10
  if (libc_version != nullptr)
336
10
    writer->json_keyvalue("glibcVersionRuntime", (*libc_version)());
337
#endif /* _WIN32 */
338
339
#ifdef __GLIBC__
340
10
  buf << __GLIBC__ << "." << __GLIBC_MINOR__;
341
10
  writer->json_keyvalue("glibcVersionCompiler", buf.str());
342
10
  buf.str("");
343
#endif
344
345
  // Report Process word size
346
10
  writer->json_keyvalue("wordSize", sizeof(void*) * 8);
347
10
  writer->json_keyvalue("arch", node::per_process::metadata.arch);
348
10
  writer->json_keyvalue("platform", node::per_process::metadata.platform);
349
350
  // Report deps component versions
351
10
  PrintComponentVersions(writer);
352
353
  // Report release metadata.
354
10
  PrintRelease(writer);
355
356
  // Report operating system and machine information
357
  uv_utsname_t os_info;
358
359
10
  if (uv_os_uname(&os_info) == 0) {
360
10
    writer->json_keyvalue("osName", os_info.sysname);
361
10
    writer->json_keyvalue("osRelease", os_info.release);
362
10
    writer->json_keyvalue("osVersion", os_info.version);
363
10
    writer->json_keyvalue("osMachine", os_info.machine);
364
  }
365
366
  char host[UV_MAXHOSTNAMESIZE];
367
10
  size_t host_size = sizeof(host);
368
369
10
  if (uv_os_gethostname(host, &host_size) == 0)
370
10
    writer->json_keyvalue("host", host);
371
10
}
372
373
// Report the JavaScript stack.
374
10
static void PrintJavaScriptStack(JSONWriter* writer,
375
                                 Isolate* isolate,
376
                                 Local<String> stackstr,
377
                                 const char* location) {
378
10
  writer->json_objectstart("javascriptStack");
379
380
10
  std::string ss;
381

20
  if ((!strcmp(location, "OnFatalError")) ||
382
10
      (!strcmp(location, "OnUserSignal"))) {
383
    ss = "No stack.\nUnavailable.\n";
384
  } else {
385
10
    String::Utf8Value sv(isolate, stackstr);
386
10
    ss = std::string(*sv, sv.length());
387
  }
388
10
  int line = ss.find("\n");
389
10
  if (line == -1) {
390
    writer->json_keyvalue("message", ss);
391
    writer->json_objectend();
392
  } else {
393
10
    std::string l = ss.substr(0, line);
394
10
    writer->json_keyvalue("message", l);
395
10
    writer->json_arraystart("stack");
396
10
    ss = ss.substr(line + 1);
397
10
    line = ss.find("\n");
398
92
    while (line != -1) {
399
72
      l = ss.substr(0, line);
400
360
      l.erase(l.begin(), std::find_if(l.begin(), l.end(), [](int ch) {
401
360
                return !std::iswspace(ch);
402
432
              }));
403
72
      writer->json_element(l);
404
72
      ss = ss.substr(line + 1);
405
72
      line = ss.find("\n");
406
10
    }
407
  }
408
10
  writer->json_arrayend();
409
10
  writer->json_objectend();
410
10
}
411
412
// Report a native stack backtrace
413
10
static void PrintNativeStack(JSONWriter* writer) {
414
10
  auto sym_ctx = NativeSymbolDebuggingContext::New();
415
  void* frames[256];
416
10
  const int size = sym_ctx->GetStackTrace(frames, arraysize(frames));
417
10
  writer->json_arraystart("nativeStack");
418
  int i;
419
80
  for (i = 1; i < size; i++) {
420
70
    void* frame = frames[i];
421
70
    writer->json_start();
422
    writer->json_keyvalue("pc",
423
70
                          ValueToHexString(reinterpret_cast<uintptr_t>(frame)));
424
70
    writer->json_keyvalue("symbol", sym_ctx->LookupSymbol(frame).Display());
425
70
    writer->json_end();
426
  }
427
10
  writer->json_arrayend();
428
10
}
429
430
// Report V8 JavaScript heap information.
431
// This uses the existing V8 HeapStatistics and HeapSpaceStatistics APIs.
432
// The isolate->GetGCStatistics(&heap_stats) internal V8 API could potentially
433
// provide some more useful information - the GC history and the handle counts
434
10
static void PrintGCStatistics(JSONWriter* writer, Isolate* isolate) {
435
10
  HeapStatistics v8_heap_stats;
436
10
  isolate->GetHeapStatistics(&v8_heap_stats);
437
10
  HeapSpaceStatistics v8_heap_space_stats;
438
439
10
  writer->json_objectstart("javascriptHeap");
440
10
  writer->json_keyvalue("totalMemory", v8_heap_stats.total_heap_size());
441
  writer->json_keyvalue("totalCommittedMemory",
442
10
                        v8_heap_stats.total_physical_size());
443
10
  writer->json_keyvalue("usedMemory", v8_heap_stats.used_heap_size());
444
  writer->json_keyvalue("availableMemory",
445
10
                        v8_heap_stats.total_available_size());
446
10
  writer->json_keyvalue("memoryLimit", v8_heap_stats.heap_size_limit());
447
448
10
  writer->json_objectstart("heapSpaces");
449
  // Loop through heap spaces
450
80
  for (size_t i = 0; i < isolate->NumberOfHeapSpaces(); i++) {
451
70
    isolate->GetHeapSpaceStatistics(&v8_heap_space_stats, i);
452
70
    writer->json_objectstart(v8_heap_space_stats.space_name());
453
70
    writer->json_keyvalue("memorySize", v8_heap_space_stats.space_size());
454
    writer->json_keyvalue(
455
        "committedMemory",
456
70
        v8_heap_space_stats.physical_space_size());
457
    writer->json_keyvalue(
458
        "capacity",
459
140
        v8_heap_space_stats.space_used_size() +
460
140
            v8_heap_space_stats.space_available_size());
461
70
    writer->json_keyvalue("used", v8_heap_space_stats.space_used_size());
462
    writer->json_keyvalue(
463
70
        "available", v8_heap_space_stats.space_available_size());
464
70
    writer->json_objectend();
465
  }
466
467
10
  writer->json_objectend();
468
10
  writer->json_objectend();
469
10
}
470
471
#ifndef _WIN32
472
// Report resource usage (Linux/OSX only).
473
10
static void PrintResourceUsage(JSONWriter* writer) {
474
  // Get process uptime in seconds
475
  uint64_t uptime =
476
10
      (uv_hrtime() - node::per_process::node_start_time) / (NANOS_PER_SEC);
477
10
  if (uptime == 0) uptime = 1;  // avoid division by zero.
478
479
  // Process and current thread usage statistics
480
  struct rusage stats;
481
10
  writer->json_objectstart("resourceUsage");
482
10
  if (getrusage(RUSAGE_SELF, &stats) == 0) {
483
    double user_cpu =
484
10
        stats.ru_utime.tv_sec + SEC_PER_MICROS * stats.ru_utime.tv_usec;
485
    double kernel_cpu =
486
10
        stats.ru_stime.tv_sec + SEC_PER_MICROS * stats.ru_stime.tv_usec;
487
10
    writer->json_keyvalue("userCpuSeconds", user_cpu);
488
10
    writer->json_keyvalue("kernelCpuSeconds", kernel_cpu);
489
10
    double cpu_abs = user_cpu + kernel_cpu;
490
10
    double cpu_percentage = (cpu_abs / uptime) * 100.0;
491
10
    writer->json_keyvalue("cpuConsumptionPercent", cpu_percentage);
492
10
    writer->json_keyvalue("maxRss", stats.ru_maxrss * 1024);
493
10
    writer->json_objectstart("pageFaults");
494
10
    writer->json_keyvalue("IORequired", stats.ru_majflt);
495
10
    writer->json_keyvalue("IONotRequired", stats.ru_minflt);
496
10
    writer->json_objectend();
497
10
    writer->json_objectstart("fsActivity");
498
10
    writer->json_keyvalue("reads", stats.ru_inblock);
499
10
    writer->json_keyvalue("writes", stats.ru_oublock);
500
10
    writer->json_objectend();
501
  }
502
10
  writer->json_objectend();
503
#ifdef RUSAGE_THREAD
504
10
  if (getrusage(RUSAGE_THREAD, &stats) == 0) {
505
10
    writer->json_objectstart("uvthreadResourceUsage");
506
    double user_cpu =
507
10
        stats.ru_utime.tv_sec + SEC_PER_MICROS * stats.ru_utime.tv_usec;
508
    double kernel_cpu =
509
10
        stats.ru_stime.tv_sec + SEC_PER_MICROS * stats.ru_stime.tv_usec;
510
10
    writer->json_keyvalue("userCpuSeconds", user_cpu);
511
10
    writer->json_keyvalue("kernelCpuSeconds", kernel_cpu);
512
10
    double cpu_abs = user_cpu + kernel_cpu;
513
10
    double cpu_percentage = (cpu_abs / uptime) * 100.0;
514
10
    writer->json_keyvalue("cpuConsumptionPercent", cpu_percentage);
515
10
    writer->json_objectstart("fsActivity");
516
10
    writer->json_keyvalue("reads", stats.ru_inblock);
517
10
    writer->json_keyvalue("writes", stats.ru_oublock);
518
10
    writer->json_objectend();
519
10
    writer->json_objectend();
520
  }
521
#endif
522
10
}
523
#endif
524
525
// Report operating system information.
526
10
static void PrintSystemInformation(JSONWriter* writer) {
527
#ifndef _WIN32
528
  static struct {
529
    const char* description;
530
    int id;
531
  } rlimit_strings[] = {
532
    {"core_file_size_blocks", RLIMIT_CORE},
533
    {"data_seg_size_kbytes", RLIMIT_DATA},
534
    {"file_size_blocks", RLIMIT_FSIZE},
535
#if !(defined(_AIX) || defined(__sun))
536
    {"max_locked_memory_bytes", RLIMIT_MEMLOCK},
537
#endif
538
#ifndef __sun
539
    {"max_memory_size_kbytes", RLIMIT_RSS},
540
#endif
541
    {"open_files", RLIMIT_NOFILE},
542
    {"stack_size_bytes", RLIMIT_STACK},
543
    {"cpu_time_seconds", RLIMIT_CPU},
544
#ifndef __sun
545
    {"max_user_processes", RLIMIT_NPROC},
546
#endif
547
    {"virtual_memory_kbytes", RLIMIT_AS}
548
  };
549
#endif  // _WIN32
550
10
  writer->json_objectstart("environmentVariables");
551
10
  Mutex::ScopedLock lock(node::per_process::env_var_mutex);
552
#ifdef _WIN32
553
  LPWSTR lpszVariable;
554
  LPWCH lpvEnv;
555
556
  // Get pointer to the environment block
557
  lpvEnv = GetEnvironmentStringsW();
558
  if (lpvEnv != nullptr) {
559
    // Variable strings are separated by null bytes,
560
    // and the block is terminated by a null byte.
561
    lpszVariable = reinterpret_cast<LPWSTR>(lpvEnv);
562
    while (*lpszVariable) {
563
      DWORD size = WideCharToMultiByte(
564
          CP_UTF8, 0, lpszVariable, -1, nullptr, 0, nullptr, nullptr);
565
      char* str = new char[size];
566
      WideCharToMultiByte(
567
          CP_UTF8, 0, lpszVariable, -1, str, size, nullptr, nullptr);
568
      std::string env(str);
569
      int sep = env.rfind("=");
570
      std::string key = env.substr(0, sep);
571
      std::string value = env.substr(sep + 1);
572
      writer->json_keyvalue(key, value);
573
      lpszVariable += lstrlenW(lpszVariable) + 1;
574
    }
575
    FreeEnvironmentStringsW(lpvEnv);
576
  }
577
  writer->json_objectend();
578
#else
579
20
  std::string pair;
580
640
  for (char** env = environ; *env != nullptr; ++env) {
581
630
    std::string pair(*env);
582
630
    int separator = pair.find('=');
583
1260
    std::string key = pair.substr(0, separator);
584
1260
    std::string str = pair.substr(separator + 1);
585
630
    writer->json_keyvalue(key, str);
586
630
  }
587
10
  writer->json_objectend();
588
589
10
  writer->json_objectstart("userLimits");
590
  struct rlimit limit;
591
20
  std::string soft, hard;
592
593
110
  for (size_t i = 0; i < arraysize(rlimit_strings); i++) {
594
100
    if (getrlimit(rlimit_strings[i].id, &limit) == 0) {
595
100
      writer->json_objectstart(rlimit_strings[i].description);
596
597
100
      if (limit.rlim_cur == RLIM_INFINITY)
598
60
        writer->json_keyvalue("soft", "unlimited");
599
      else
600
40
        writer->json_keyvalue("soft", limit.rlim_cur);
601
602
100
      if (limit.rlim_max == RLIM_INFINITY)
603
70
        writer->json_keyvalue("hard", "unlimited");
604
      else
605
30
        writer->json_keyvalue("hard", limit.rlim_max);
606
607
100
      writer->json_objectend();
608
    }
609
  }
610
10
  writer->json_objectend();
611
#endif
612
613
20
  PrintLoadedLibraries(writer);
614
10
}
615
616
// Report a list of loaded native libraries.
617
10
static void PrintLoadedLibraries(JSONWriter* writer) {
618
10
  writer->json_arraystart("sharedObjects");
619
  std::vector<std::string> modules =
620
10
      NativeSymbolDebuggingContext::GetLoadedLibraries();
621
10
  for (auto const& module_name : modules) writer->json_element(module_name);
622
10
  writer->json_arrayend();
623
10
}
624
625
// Obtain and report the node and subcomponent version strings.
626
10
static void PrintComponentVersions(JSONWriter* writer) {
627
10
  std::stringstream buf;
628
629
10
  writer->json_objectstart("componentVersions");
630
631
#define V(key)                                                                 \
632
  writer->json_keyvalue(#key, node::per_process::metadata.versions.key);
633
10
  NODE_VERSIONS_KEYS(V)
634
#undef V
635
636
10
  writer->json_objectend();
637
10
}
638
639
// Report runtime release information.
640
10
static void PrintRelease(JSONWriter* writer) {
641
10
  writer->json_objectstart("release");
642
10
  writer->json_keyvalue("name", node::per_process::metadata.release.name);
643
#if NODE_VERSION_IS_LTS
644
  writer->json_keyvalue("lts", node::per_process::metadata.release.lts);
645
#endif
646
647
#ifdef NODE_HAS_RELEASE_URLS
648
  writer->json_keyvalue("headersUrl",
649
                        node::per_process::metadata.release.headers_url);
650
  writer->json_keyvalue("sourceUrl",
651
                        node::per_process::metadata.release.source_url);
652
#ifdef _WIN32
653
  writer->json_keyvalue("libUrl", node::per_process::metadata.release.lib_url);
654
#endif  // _WIN32
655
#endif  // NODE_HAS_RELEASE_URLS
656
657
10
  writer->json_objectend();
658
10
}
659
660
10
static void LocalTime(TIME_TYPE* tm_struct) {
661
#ifdef _WIN32
662
  GetLocalTime(tm_struct);
663
#else  // UNIX, OSX
664
  struct timeval time_val;
665
10
  gettimeofday(&time_val, nullptr);
666
10
  localtime_r(&time_val.tv_sec, tm_struct);
667
#endif
668
10
}
669
670

12846
}  // namespace report