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: 1 268 0.4 %
Date: 2019-02-01 22:03:38 Branches: 2 80 2.5 %

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
#include <sys/utsname.h>
32
#endif
33
34
#include <fcntl.h>
35
#include <string.h>
36
#include <time.h>
37
#include <iomanip>
38
39
#ifndef _MSC_VER
40
#include <strings.h>
41
#endif
42
43
#ifdef __APPLE__
44
#include <mach-o/dyld.h>
45
#endif
46
47
#ifndef _WIN32
48
extern char** environ;
49
#endif
50
51
namespace report {
52
using node::arraysize;
53
using node::Environment;
54
using node::Mutex;
55
using node::NativeSymbolDebuggingContext;
56
using node::PerIsolateOptions;
57
using v8::HeapSpaceStatistics;
58
using v8::HeapStatistics;
59
using v8::Isolate;
60
using v8::Local;
61
using v8::Number;
62
using v8::StackTrace;
63
using v8::String;
64
using v8::V8;
65
using v8::Value;
66
67
// Internal/static function declarations
68
static void WriteNodeReport(Isolate* isolate,
69
                            Environment* env,
70
                            const char* message,
71
                            const char* location,
72
                            const std::string& filename,
73
                            std::ostream& out,
74
                            Local<String> stackstr,
75
                            TIME_TYPE* time);
76
static void PrintVersionInformation(JSONWriter* writer);
77
static void PrintJavaScriptStack(JSONWriter* writer,
78
                                 Isolate* isolate,
79
                                 Local<String> stackstr,
80
                                 const char* location);
81
static void PrintNativeStack(JSONWriter* writer);
82
#ifndef _WIN32
83
static void PrintResourceUsage(JSONWriter* writer);
84
#endif
85
static void PrintGCStatistics(JSONWriter* writer, Isolate* isolate);
86
static void PrintSystemInformation(JSONWriter* writer);
87
static void PrintLoadedLibraries(JSONWriter* writer);
88
static void PrintComponentVersions(JSONWriter* writer);
89
static void PrintRelease(JSONWriter* writer);
90
static void LocalTime(TIME_TYPE* tm_struct);
91
92
// Global variables
93
static std::atomic_int seq = {0};  // sequence number for report filenames
94
95
// External function to trigger a report, writing to file.
96
// The 'name' parameter is in/out: an input filename is used
97
// if supplied, and the actual filename is returned.
98
std::string TriggerNodeReport(Isolate* isolate,
99
                              Environment* env,
100
                              const char* message,
101
                              const char* location,
102
                              std::string name,
103
                              Local<String> stackstr) {
104
  std::ostringstream oss;
105
  std::string filename;
106
  std::shared_ptr<PerIsolateOptions> options;
107
  if (env != nullptr) options = env->isolate_data()->options();
108
109
  // Obtain the current time and the pid (platform dependent)
110
  TIME_TYPE tm_struct;
111
  LocalTime(&tm_struct);
112
  uv_pid_t pid = uv_os_getpid();
113
  // Determine the required report filename. In order of priority:
114
  //   1) supplied on API 2) configured on startup 3) default generated
115
  if (!name.empty()) {
116
    // Filename was specified as API parameter, use that
117
    oss << name;
118
  } else if (env != nullptr && options->report_filename.length() > 0) {
119
    // File name was supplied via start-up option, use that
120
    oss << options->report_filename;
121
  } else {
122
    // Construct the report filename, with timestamp, pid and sequence number
123
    oss << "report";
124
    seq++;
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
    oss << "." << pid;
133
    oss << "." << std::setfill('0') << std::setw(3) << seq.load();
134
#else  // UNIX, OSX
135
    oss << "." << std::setfill('0') << std::setw(4) << tm_struct.tm_year + 1900;
136
    oss << std::setfill('0') << std::setw(2) << tm_struct.tm_mon + 1;
137
    oss << std::setfill('0') << std::setw(2) << tm_struct.tm_mday;
138
    oss << "." << std::setfill('0') << std::setw(2) << tm_struct.tm_hour;
139
    oss << std::setfill('0') << std::setw(2) << tm_struct.tm_min;
140
    oss << std::setfill('0') << std::setw(2) << tm_struct.tm_sec;
141
    oss << "." << pid;
142
    oss << "." << std::setfill('0') << std::setw(3) << seq.load();
143
#endif
144
    oss << ".json";
145
  }
146
147
  filename = oss.str();
148
  // Open the report file stream for writing. Supports stdout/err,
149
  // user-specified or (default) generated name
150
  std::ofstream outfile;
151
  std::ostream* outstream = &std::cout;
152
  if (filename == "stdout") {
153
    outstream = &std::cout;
154
  } else if (filename == "stderr") {
155
    outstream = &std::cerr;
156
  } else {
157
    // Regular file. Append filename to directory path if one was specified
158
    if (env != nullptr && options->report_directory.length() > 0) {
159
      std::string pathname = options->report_directory;
160
      pathname += PATHSEP;
161
      pathname += filename;
162
      outfile.open(pathname, std::ios::out | std::ios::binary);
163
    } else {
164
      outfile.open(filename, std::ios::out | std::ios::binary);
165
    }
166
    // Check for errors on the file open
167
    if (!outfile.is_open()) {
168
      if (env != nullptr && options->report_directory.length() > 0) {
169
        std::cerr << std::endl
170
                  << "Failed to open Node.js report file: " << filename
171
                  << " directory: " << options->report_directory
172
                  << " (errno: " << errno << ")" << std::endl;
173
      } else {
174
        std::cerr << std::endl
175
                  << "Failed to open Node.js report file: " << filename
176
                  << " (errno: " << errno << ")" << std::endl;
177
      }
178
      return "";
179
    } else {
180
      std::cerr << std::endl
181
                << "Writing Node.js report to file: " << filename << std::endl;
182
    }
183
  }
184
185
  // Pass our stream about by reference, not by copying it.
186
  std::ostream& out = outfile.is_open() ? outfile : *outstream;
187
188
  WriteNodeReport(
189
      isolate, env, message, location, filename, out, stackstr, &tm_struct);
190
191
  // Do not close stdout/stderr, only close files we opened.
192
  if (outfile.is_open()) {
193
    outfile.close();
194
  }
195
196
  std::cerr << "Node.js report completed" << std::endl;
197
  if (name.empty()) return filename;
198
  return name;
199
}
200
201
// External function to trigger a report, writing to a supplied stream.
202
void GetNodeReport(Isolate* isolate,
203
                   Environment* env,
204
                   const char* message,
205
                   const char* location,
206
                   Local<String> stackstr,
207
                   std::ostream& out) {
208
  // Obtain the current time and the pid (platform dependent)
209
  TIME_TYPE tm_struct;
210
  LocalTime(&tm_struct);
211
  std::string str = "NA";
212
  WriteNodeReport(
213
      isolate, env, message, location, str, out, stackstr, &tm_struct);
214
}
215
216
// Internal function to coordinate and write the various
217
// sections of the report to the supplied stream
218
static void WriteNodeReport(Isolate* isolate,
219
                            Environment* env,
220
                            const char* message,
221
                            const char* location,
222
                            const std::string& filename,
223
                            std::ostream& out,
224
                            Local<String> stackstr,
225
                            TIME_TYPE* tm_struct) {
226
  uv_pid_t pid = uv_os_getpid();
227
228
  // Save formatting for output stream.
229
  std::ios old_state(nullptr);
230
  old_state.copyfmt(out);
231
232
  // File stream opened OK, now start printing the report content:
233
  // the title and header information (event, filename, timestamp and pid)
234
235
  JSONWriter writer(out);
236
  writer.json_start();
237
  writer.json_objectstart("header");
238
239
  writer.json_keyvalue("event", message);
240
  writer.json_keyvalue("location", location);
241
  if (!filename.empty())
242
    writer.json_keyvalue("filename", filename);
243
  else
244
    writer.json_keyvalue("filename", "''");
245
246
  // Report dump event and module load date/time stamps
247
  char timebuf[64];
248
#ifdef _WIN32
249
  snprintf(timebuf,
250
           sizeof(timebuf),
251
           "%4d-%02d-%02dT%02d:%02d:%02dZ",
252
           tm_struct->wYear,
253
           tm_struct->wMonth,
254
           tm_struct->wDay,
255
           tm_struct->wHour,
256
           tm_struct->wMinute,
257
           tm_struct->wSecond);
258
  writer.json_keyvalue("dumpEventTime", timebuf);
259
#else  // UNIX, OSX
260
  snprintf(timebuf,
261
           sizeof(timebuf),
262
           "%4d-%02d-%02dT%02d:%02d:%02dZ",
263
           tm_struct->tm_year + 1900,
264
           tm_struct->tm_mon + 1,
265
           tm_struct->tm_mday,
266
           tm_struct->tm_hour,
267
           tm_struct->tm_min,
268
           tm_struct->tm_sec);
269
  writer.json_keyvalue("dumpEventTime", timebuf);
270
  struct timeval ts;
271
  gettimeofday(&ts, nullptr);
272
  writer.json_keyvalue("dumpEventTimeStamp",
273
                       std::to_string(ts.tv_sec * 1000 + ts.tv_usec / 1000));
274
#endif
275
  // Report native process ID
276
  writer.json_keyvalue("processId", pid);
277
278
  // Report out the command line.
279
  if (!node::per_process::cli_options->cmdline.empty()) {
280
    writer.json_arraystart("commandLine");
281
    for (std::string arg : node::per_process::cli_options->cmdline) {
282
      writer.json_element(arg);
283
    }
284
    writer.json_arrayend();
285
  }
286
287
  // Report Node.js and OS version information
288
  PrintVersionInformation(&writer);
289
  writer.json_objectend();
290
291
  // Report summary JavaScript stack backtrace
292
  PrintJavaScriptStack(&writer, isolate, stackstr, location);
293
294
  // Report native stack backtrace
295
  PrintNativeStack(&writer);
296
297
  // Report V8 Heap and Garbage Collector information
298
  PrintGCStatistics(&writer, isolate);
299
300
  // Report OS and current thread resource usage
301
#ifndef _WIN32
302
  PrintResourceUsage(&writer);
303
#endif
304
305
  writer.json_arraystart("libuv");
306
  if (env != nullptr)
307
    uv_walk(env->event_loop(), WalkHandle, static_cast<void*>(&writer));
308
309
  writer.json_arrayend();
310
311
  // Report operating system information
312
  PrintSystemInformation(&writer);
313
314
  writer.json_objectend();
315
316
  // Restore output stream formatting.
317
  out.copyfmt(old_state);
318
}
319
320
// Report Node.js version, OS version and machine information.
321
static void PrintVersionInformation(JSONWriter* writer) {
322
  std::ostringstream buf;
323
  // Report Node version
324
  buf << "v" << NODE_VERSION_STRING;
325
  writer->json_keyvalue("nodejsVersion", buf.str());
326
  buf.str("");
327
328
#ifndef _WIN32
329
  // Report compiler and runtime glibc versions where possible.
330
  const char* (*libc_version)();
331
  *(reinterpret_cast<void**>(&libc_version)) =
332
      dlsym(RTLD_DEFAULT, "gnu_get_libc_version");
333
  if (libc_version != nullptr)
334
    writer->json_keyvalue("glibcVersionRuntime", (*libc_version)());
335
#endif /* _WIN32 */
336
337
#ifdef __GLIBC__
338
  buf << __GLIBC__ << "." << __GLIBC_MINOR__;
339
  writer->json_keyvalue("glibcVersionCompiler", buf.str());
340
  buf.str("");
341
#endif
342
343
  // Report Process word size
344
  writer->json_keyvalue("wordSize", sizeof(void*) * 8);
345
  writer->json_keyvalue("arch", node::per_process::metadata.arch);
346
  writer->json_keyvalue("platform", node::per_process::metadata.platform);
347
348
  // Report deps component versions
349
  PrintComponentVersions(writer);
350
351
  // Report release metadata.
352
  PrintRelease(writer);
353
354
  // Report operating system and machine information (Windows)
355
#ifdef _WIN32
356
  {
357
    // Level 101 to obtain the server name, type, and associated details.
358
    // ref: https://docs.microsoft.com/en-us/windows/desktop/
359
    // api/lmserver/nf-lmserver-netservergetinfo
360
    const DWORD level = 101;
361
    LPSERVER_INFO_101 os_info = nullptr;
362
    NET_API_STATUS nStatus =
363
        NetServerGetInfo(nullptr, level, reinterpret_cast<LPBYTE*>(&os_info));
364
    if (nStatus == NERR_Success) {
365
      LPSTR os_name = "Windows";
366
      const DWORD major = os_info->sv101_version_major & MAJOR_VERSION_MASK;
367
      const DWORD type = os_info->sv101_type;
368
      const bool isServer = (type & SV_TYPE_DOMAIN_CTRL) ||
369
                            (type & SV_TYPE_DOMAIN_BAKCTRL) ||
370
                            (type & SV_TYPE_SERVER_NT);
371
      switch (major) {
372
        case 5:
373
          switch (os_info->sv101_version_minor) {
374
            case 0:
375
              os_name = "Windows 2000";
376
              break;
377
            default:
378
              os_name = (isServer ? "Windows Server 2003" : "Windows XP");
379
          }
380
          break;
381
        case 6:
382
          switch (os_info->sv101_version_minor) {
383
            case 0:
384
              os_name = (isServer ? "Windows Server 2008" : "Windows Vista");
385
              break;
386
            case 1:
387
              os_name = (isServer ? "Windows Server 2008 R2" : "Windows 7");
388
              break;
389
            case 2:
390
              os_name = (isServer ? "Windows Server 2012" : "Windows 8");
391
              break;
392
            case 3:
393
              os_name = (isServer ? "Windows Server 2012 R2" : "Windows 8.1");
394
              break;
395
            default:
396
              os_name = (isServer ? "Windows Server" : "Windows Client");
397
          }
398
          break;
399
        case 10:
400
          os_name = (isServer ? "Windows Server 2016" : "Windows 10");
401
          break;
402
        default:
403
          os_name = (isServer ? "Windows Server" : "Windows Client");
404
      }
405
      writer->json_keyvalue("osVersion", os_name);
406
407
      // Convert and report the machine name and comment fields
408
      // (these are LPWSTR types)
409
      size_t count;
410
      char name_buf[256];
411
      wcstombs_s(
412
          &count, name_buf, sizeof(name_buf), os_info->sv101_name, _TRUNCATE);
413
      if (os_info->sv101_comment != nullptr) {
414
        char comment_buf[256];
415
        wcstombs_s(&count,
416
                   comment_buf,
417
                   sizeof(comment_buf),
418
                   os_info->sv101_comment,
419
                   _TRUNCATE);
420
        buf << name_buf << " " << comment_buf;
421
        writer->json_keyvalue("machine", buf.str());
422
        buf.flush();
423
      } else {
424
        writer->json_keyvalue("machine", name_buf);
425
      }
426
427
      if (os_info != nullptr) {
428
        NetApiBufferFree(os_info);
429
      }
430
    } else {
431
      // NetServerGetInfo() failed, fallback to use GetComputerName() instead
432
      TCHAR machine_name[256];
433
      DWORD machine_name_size = 256;
434
      writer->json_keyvalue("osVersion", "Windows");
435
      if (GetComputerName(machine_name, &machine_name_size)) {
436
        writer->json_keyvalue("machine", machine_name);
437
      }
438
    }
439
  }
440
#else
441
  // Report operating system and machine information (Unix/OSX)
442
  struct utsname os_info;
443
  if (uname(&os_info) >= 0) {
444
#ifdef _AIX
445
    buf << os_info.sysname << " " << os_info.version << "." << os_info.release;
446
#else
447
    buf << os_info.sysname << " " << os_info.release << " " << os_info.version;
448
#endif /* _AIX */
449
    writer->json_keyvalue("osVersion", buf.str());
450
    buf.str("");
451
    buf << os_info.nodename << " " << os_info.machine;
452
    writer->json_keyvalue("machine", buf.str());
453
  }
454
#endif
455
}
456
457
// Report the JavaScript stack.
458
static void PrintJavaScriptStack(JSONWriter* writer,
459
                                 Isolate* isolate,
460
                                 Local<String> stackstr,
461
                                 const char* location) {
462
  writer->json_objectstart("javascriptStack");
463
464
  std::string ss;
465
  if ((!strcmp(location, "OnFatalError")) ||
466
      (!strcmp(location, "OnUserSignal"))) {
467
    ss = "No stack.\nUnavailable.\n";
468
  } else {
469
    String::Utf8Value sv(isolate, stackstr);
470
    ss = std::string(*sv, sv.length());
471
  }
472
  int line = ss.find("\n");
473
  if (line == -1) {
474
    writer->json_keyvalue("message", ss);
475
    writer->json_objectend();
476
  } else {
477
    std::string l = ss.substr(0, line);
478
    writer->json_keyvalue("message", l);
479
    writer->json_arraystart("stack");
480
    ss = ss.substr(line + 1);
481
    line = ss.find("\n");
482
    while (line != -1) {
483
      l = ss.substr(0, line);
484
      l.erase(l.begin(), std::find_if(l.begin(), l.end(), [](int ch) {
485
                return !std::iswspace(ch);
486
              }));
487
      writer->json_element(l);
488
      ss = ss.substr(line + 1);
489
      line = ss.find("\n");
490
    }
491
  }
492
  writer->json_arrayend();
493
  writer->json_objectend();
494
}
495
496
// Report a native stack backtrace
497
static void PrintNativeStack(JSONWriter* writer) {
498
  auto sym_ctx = NativeSymbolDebuggingContext::New();
499
  void* frames[256];
500
  const int size = sym_ctx->GetStackTrace(frames, arraysize(frames));
501
  writer->json_arraystart("nativeStack");
502
  int i;
503
  std::ostringstream buf;
504
  for (i = 1; i < size; i++) {
505
    void* frame = frames[i];
506
    buf.str("");
507
    buf << " [pc=" << frame << "] ";
508
    buf << sym_ctx->LookupSymbol(frame).Display().c_str();
509
    writer->json_element(buf.str());
510
  }
511
  writer->json_arrayend();
512
}
513
514
// Report V8 JavaScript heap information.
515
// This uses the existing V8 HeapStatistics and HeapSpaceStatistics APIs.
516
// The isolate->GetGCStatistics(&heap_stats) internal V8 API could potentially
517
// provide some more useful information - the GC history and the handle counts
518
static void PrintGCStatistics(JSONWriter* writer, Isolate* isolate) {
519
  HeapStatistics v8_heap_stats;
520
  isolate->GetHeapStatistics(&v8_heap_stats);
521
  HeapSpaceStatistics v8_heap_space_stats;
522
523
  writer->json_objectstart("javascriptHeap");
524
  writer->json_keyvalue("totalMemory", v8_heap_stats.total_heap_size());
525
  writer->json_keyvalue("totalCommittedMemory",
526
                        v8_heap_stats.total_physical_size());
527
  writer->json_keyvalue("usedMemory", v8_heap_stats.used_heap_size());
528
  writer->json_keyvalue("availableMemory",
529
                        v8_heap_stats.total_available_size());
530
  writer->json_keyvalue("memoryLimit", v8_heap_stats.heap_size_limit());
531
532
  writer->json_objectstart("heapSpaces");
533
  // Loop through heap spaces
534
  size_t i;
535
  for (i = 0; i < isolate->NumberOfHeapSpaces() - 1; i++) {
536
    isolate->GetHeapSpaceStatistics(&v8_heap_space_stats, i);
537
    writer->json_objectstart(v8_heap_space_stats.space_name());
538
    writer->json_keyvalue("memorySize", v8_heap_space_stats.space_size());
539
    writer->json_keyvalue(
540
        "committedMemory",
541
        v8_heap_space_stats.physical_space_size());
542
    writer->json_keyvalue(
543
        "capacity",
544
        v8_heap_space_stats.space_used_size() +
545
            v8_heap_space_stats.space_available_size());
546
    writer->json_keyvalue("used", v8_heap_space_stats.space_used_size());
547
    writer->json_keyvalue(
548
        "available", v8_heap_space_stats.space_available_size());
549
    writer->json_objectend();
550
  }
551
  isolate->GetHeapSpaceStatistics(&v8_heap_space_stats, i);
552
  writer->json_objectstart(v8_heap_space_stats.space_name());
553
  writer->json_keyvalue("memorySize", v8_heap_space_stats.space_size());
554
  writer->json_keyvalue(
555
      "committedMemory", v8_heap_space_stats.physical_space_size());
556
  writer->json_keyvalue(
557
      "capacity",
558
      v8_heap_space_stats.space_used_size() +
559
          v8_heap_space_stats.space_available_size());
560
  writer->json_keyvalue("used", v8_heap_space_stats.space_used_size());
561
  writer->json_keyvalue(
562
      "available", v8_heap_space_stats.space_available_size());
563
  writer->json_objectend();
564
  writer->json_objectend();
565
  writer->json_objectend();
566
}
567
568
#ifndef _WIN32
569
// Report resource usage (Linux/OSX only).
570
static void PrintResourceUsage(JSONWriter* writer) {
571
  time_t current_time;  // current time absolute
572
  time(&current_time);
573
  size_t boot_time = static_cast<time_t>(node::per_process::prog_start_time /
574
                                         (1000 * 1000 * 1000));
575
  auto uptime = difftime(current_time, boot_time);
576
  if (uptime == 0) uptime = 1;  // avoid division by zero.
577
578
  // Process and current thread usage statistics
579
  struct rusage stats;
580
  writer->json_objectstart("resourceUsage");
581
  if (getrusage(RUSAGE_SELF, &stats) == 0) {
582
    double user_cpu = stats.ru_utime.tv_sec + 0.000001 * stats.ru_utime.tv_usec;
583
    double kernel_cpu =
584
        stats.ru_utime.tv_sec + 0.000001 * stats.ru_utime.tv_usec;
585
    writer->json_keyvalue("userCpuSeconds", user_cpu);
586
    writer->json_keyvalue("kernelCpuSeconds", kernel_cpu);
587
    double cpu_abs = user_cpu + kernel_cpu;
588
    double cpu_percentage = (cpu_abs / uptime) * 100.0;
589
    writer->json_keyvalue("cpuConsumptionPercent", cpu_percentage);
590
    writer->json_keyvalue("maxRss", stats.ru_maxrss * 1024);
591
    writer->json_objectstart("pageFaults");
592
    writer->json_keyvalue("IORequired", stats.ru_majflt);
593
    writer->json_keyvalue("IONotRequired", stats.ru_minflt);
594
    writer->json_objectend();
595
    writer->json_objectstart("fsActivity");
596
    writer->json_keyvalue("reads", stats.ru_inblock);
597
    writer->json_keyvalue("writes", stats.ru_oublock);
598
    writer->json_objectend();
599
  }
600
  writer->json_objectend();
601
#ifdef RUSAGE_THREAD
602
  if (getrusage(RUSAGE_THREAD, &stats) == 0) {
603
    writer->json_objectstart("uvthreadResourceUsage");
604
    double user_cpu = stats.ru_utime.tv_sec + 0.000001 * stats.ru_utime.tv_usec;
605
    double kernel_cpu =
606
        stats.ru_utime.tv_sec + 0.000001 * stats.ru_utime.tv_usec;
607
    writer->json_keyvalue("userCpuSeconds", user_cpu);
608
    writer->json_keyvalue("kernelCpuSeconds", kernel_cpu);
609
    double cpu_abs = user_cpu + kernel_cpu;
610
    double cpu_percentage = (cpu_abs / uptime) * 100.0;
611
    writer->json_keyvalue("cpuConsumptionPercent", cpu_percentage);
612
    writer->json_objectstart("fsActivity");
613
    writer->json_keyvalue("reads", stats.ru_inblock);
614
    writer->json_keyvalue("writes", stats.ru_oublock);
615
    writer->json_objectend();
616
    writer->json_objectend();
617
  }
618
#endif
619
}
620
#endif
621
622
// Report operating system information.
623
static void PrintSystemInformation(JSONWriter* writer) {
624
#ifndef _WIN32
625
  static struct {
626
    const char* description;
627
    int id;
628
  } rlimit_strings[] = {
629
    {"core_file_size_blocks", RLIMIT_CORE},
630
    {"data_seg_size_kbytes", RLIMIT_DATA},
631
    {"file_size_blocks", RLIMIT_FSIZE},
632
#if !(defined(_AIX) || defined(__sun))
633
    {"max_locked_memory_bytes", RLIMIT_MEMLOCK},
634
#endif
635
#ifndef __sun
636
    {"max_memory_size_kbytes", RLIMIT_RSS},
637
#endif
638
    {"open_files", RLIMIT_NOFILE},
639
    {"stack_size_bytes", RLIMIT_STACK},
640
    {"cpu_time_seconds", RLIMIT_CPU},
641
#ifndef __sun
642
    {"max_user_processes", RLIMIT_NPROC},
643
#endif
644
    {"virtual_memory_kbytes", RLIMIT_AS}
645
  };
646
#endif  // _WIN32
647
  writer->json_objectstart("environmentVariables");
648
  Mutex::ScopedLock lock(node::per_process::env_var_mutex);
649
#ifdef _WIN32
650
  LPWSTR lpszVariable;
651
  LPWCH lpvEnv;
652
653
  // Get pointer to the environment block
654
  lpvEnv = GetEnvironmentStringsW();
655
  if (lpvEnv != nullptr) {
656
    // Variable strings are separated by null bytes,
657
    // and the block is terminated by a null byte.
658
    lpszVariable = reinterpret_cast<LPWSTR>(lpvEnv);
659
    while (*lpszVariable) {
660
      DWORD size = WideCharToMultiByte(
661
          CP_UTF8, 0, lpszVariable, -1, nullptr, 0, nullptr, nullptr);
662
      char* str = new char[size];
663
      WideCharToMultiByte(
664
          CP_UTF8, 0, lpszVariable, -1, str, size, nullptr, nullptr);
665
      std::string env(str);
666
      int sep = env.rfind("=");
667
      std::string key = env.substr(0, sep);
668
      std::string value = env.substr(sep + 1);
669
      writer->json_keyvalue(key, value);
670
      lpszVariable += lstrlenW(lpszVariable) + 1;
671
    }
672
    FreeEnvironmentStringsW(lpvEnv);
673
  }
674
  writer->json_objectend();
675
#else
676
  std::string pair;
677
  for (char** env = environ; *env != nullptr; ++env) {
678
    std::string pair(*env);
679
    int separator = pair.find('=');
680
    std::string key = pair.substr(0, separator);
681
    std::string str = pair.substr(separator + 1);
682
    writer->json_keyvalue(key, str);
683
  }
684
  writer->json_objectend();
685
686
  writer->json_objectstart("userLimits");
687
  struct rlimit limit;
688
  std::string soft, hard;
689
690
  for (size_t i = 0; i < arraysize(rlimit_strings); i++) {
691
    if (getrlimit(rlimit_strings[i].id, &limit) == 0) {
692
      writer->json_objectstart(rlimit_strings[i].description);
693
694
      if (limit.rlim_cur == RLIM_INFINITY)
695
        writer->json_keyvalue("soft", "unlimited");
696
      else
697
        writer->json_keyvalue("soft", limit.rlim_cur);
698
699
      if (limit.rlim_max == RLIM_INFINITY)
700
        writer->json_keyvalue("hard", "unlimited");
701
      else
702
        writer->json_keyvalue("hard", limit.rlim_max);
703
704
      writer->json_objectend();
705
    }
706
  }
707
  writer->json_objectend();
708
#endif
709
710
  PrintLoadedLibraries(writer);
711
}
712
713
// Report a list of loaded native libraries.
714
static void PrintLoadedLibraries(JSONWriter* writer) {
715
  writer->json_arraystart("sharedObjects");
716
  std::vector<std::string> modules =
717
      NativeSymbolDebuggingContext::GetLoadedLibraries();
718
  for (auto const& module_name : modules) writer->json_element(module_name);
719
  writer->json_arrayend();
720
}
721
722
// Obtain and report the node and subcomponent version strings.
723
static void PrintComponentVersions(JSONWriter* writer) {
724
  std::stringstream buf;
725
726
  writer->json_objectstart("componentVersions");
727
728
#define V(key)                                                                 \
729
  writer->json_keyvalue(#key, node::per_process::metadata.versions.key);
730
  NODE_VERSIONS_KEYS(V)
731
#undef V
732
733
  writer->json_objectend();
734
}
735
736
// Report runtime release information.
737
static void PrintRelease(JSONWriter* writer) {
738
  writer->json_objectstart("release");
739
  writer->json_keyvalue("name", node::per_process::metadata.release.name);
740
#if NODE_VERSION_IS_LTS
741
  writer->json_keyvalue("lts", node::per_process::metadata.release.lts);
742
#endif
743
744
#ifdef NODE_HAS_RELEASE_URLS
745
  writer->json_keyvalue("headersUrl",
746
                        node::per_process::metadata.release.headers_url);
747
  writer->json_keyvalue("sourceUrl",
748
                        node::per_process::metadata.release.source_url);
749
#ifdef _WIN32
750
  writer->json_keyvalue("libUrl", node::per_process::metadata.release.lib_url);
751
#endif  // _WIN32
752
#endif  // NODE_HAS_RELEASE_URLS
753
754
  writer->json_objectend();
755
}
756
757
static void LocalTime(TIME_TYPE* tm_struct) {
758
#ifdef _WIN32
759
  GetLocalTime(tm_struct);
760
#else  // UNIX, OSX
761
  struct timeval time_val;
762
  gettimeofday(&time_val, nullptr);
763
  localtime_r(&time_val.tv_sec, tm_struct);
764
#endif
765
}
766
767

492
}  // namespace report