tracing: add lttng support for tracing on linux
authorGlen Keane <glenkeane.94@gmail.com>
Thu, 22 Jan 2015 12:35:16 +0000 (12:35 +0000)
committerBen Noordhuis <info@bnoordhuis.nl>
Mon, 9 Feb 2015 17:06:57 +0000 (18:06 +0100)
This commit adds the ability to enable userspace tracing with lttng
in io.js. It adds tracepoints for all the equivalent dtrace and ETW
tracepoints. To use these tracepoints enable --with-lttng on linux.

PR-URL: https://github.com/iojs/io.js/pull/702
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Ryan Graham <ryan@strongloop.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
14 files changed:
Makefile
configure
lib/_http_client.js
lib/_http_server.js
lib/net.js
node.gyp
src/node.cc
src/node_lttng.cc [new file with mode: 0644]
src/node_lttng.h [new file with mode: 0644]
src/node_lttng_provider.h [new file with mode: 0644]
src/node_lttng_tp.h [new file with mode: 0644]
src/nolttng_macros.py [new file with mode: 0644]
test/common.js
test/sequential/test-util-debug.js

index fdbf4d7..3974109 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -385,8 +385,9 @@ jslint:
 
 CPPLINT_EXCLUDE ?=
 CPPLINT_EXCLUDE += src/node_dtrace.cc
-CPPLINT_EXCLUDE += src/node_dtrace.cc
+CPPLINT_EXCLUDE += src/node_lttng.cc
 CPPLINT_EXCLUDE += src/node_root_certs.h
+CPPLINT_EXCLUDE += src/node_lttng_tp.h
 CPPLINT_EXCLUDE += src/node_win32_perfctr_provider.cc
 CPPLINT_EXCLUDE += src/queue.h
 CPPLINT_EXCLUDE += src/tree.h
index e85621e..d632326 100755 (executable)
--- a/configure
+++ b/configure
@@ -213,6 +213,11 @@ parser.add_option('--with-dtrace',
     dest='with_dtrace',
     help='build with DTrace (default is true on sunos)')
 
+parser.add_option('--with-lttng',
+    action='store_true',
+    dest='with_lttng',
+    help='build with Lttng (Only available to Linux)')
+
 parser.add_option('--with-etw',
     action='store_true',
     dest='with_etw',
@@ -524,6 +529,15 @@ def configure_node(o):
   else:
     o['variables']['node_use_dtrace'] = 'false'
 
+  # Enable Lttng if --with-lttng was defined. Use logic similar to
+  # ETW for windows. Lttng is only available on the Linux platform.
+  if flavor == 'linux':
+    o['variables']['node_use_lttng'] = b(options.with_lttng)
+  elif options.with_lttng:
+    raise Exception('lttng is only supported on Linux.')
+  else:
+    o['variables']['node_use_lttng'] = 'false'
+
   # if we're on illumos based systems wrap the helper library into the
   # executable
   if flavor == 'solaris':
index 6804157..b02ab66 100644 (file)
@@ -155,6 +155,7 @@ ClientRequest.prototype.aborted = undefined;
 
 ClientRequest.prototype._finish = function() {
   DTRACE_HTTP_CLIENT_REQUEST(this, this.connection);
+  LTTNG_HTTP_CLIENT_REQUEST(this, this.connection);
   COUNTER_HTTP_CLIENT_REQUEST();
   OutgoingMessage.prototype._finish.call(this);
 };
@@ -386,6 +387,7 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
 
 
   DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
+  LTTNG_HTTP_CLIENT_RESPONSE(socket, req);
   COUNTER_HTTP_CLIENT_RESPONSE();
   req.res = res;
   res.req = req;
index d8b9799..9990302 100644 (file)
@@ -92,6 +92,7 @@ util.inherits(ServerResponse, OutgoingMessage);
 
 ServerResponse.prototype._finish = function() {
   DTRACE_HTTP_SERVER_RESPONSE(this.connection);
+  LTTNG_HTTP_SERVER_RESPONSE(this.connection);
   COUNTER_HTTP_SERVER_RESPONSE();
   OutgoingMessage.prototype._finish.call(this);
 };
@@ -416,6 +417,7 @@ function connectionListener(socket) {
 
     res.shouldKeepAlive = shouldKeepAlive;
     DTRACE_HTTP_SERVER_REQUEST(req, socket);
+    LTTNG_HTTP_SERVER_REQUEST(req, socket);
     COUNTER_HTTP_SERVER_REQUEST();
 
     if (socket._httpMessage) {
index af8c3dd..030083d 100644 (file)
@@ -387,6 +387,7 @@ Socket.prototype.end = function(data, encoding) {
   stream.Duplex.prototype.end.call(this, data, encoding);
   this.writable = false;
   DTRACE_NET_STREAM_END(this);
+  LTTNG_NET_STREAM_END(this);
 
   // just in case we're waiting for an EOF.
   if (this.readable && !this._readableState.endEmitted)
@@ -1324,6 +1325,7 @@ function onconnection(err, clientHandle) {
   socket.server = self;
 
   DTRACE_NET_SERVER_CONNECTION(socket);
+  LTTNG_NET_SERVER_CONNECTION(socket);
   COUNTER_NET_SERVER_CONNECTION(socket);
   self.emit('connection', socket);
 }
index 2874f13..8506b28 100644 (file)
--- a/node.gyp
+++ b/node.gyp
@@ -2,6 +2,7 @@
   'variables': {
     'v8_use_snapshot%': 'false',
     'node_use_dtrace%': 'false',
+    'node_use_lttng%': 'false',
     'node_use_etw%': 'false',
     'node_use_perfctr%': 'false',
     'node_has_winsdk%': 'false',
             }
           ] ]
         } ],
+        [ 'node_use_lttng=="true"', {
+          'defines': [ 'HAVE_LTTNG=1' ],
+          'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)' ],
+          'libraries': [ '-llttng-ust' ],
+          'sources': [
+            'src/node_lttng.cc'
+          ],
+        } ],
         [ 'node_use_mdb=="true"', {
           'dependencies': [ 'node_mdb' ],
           'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)' ],
             [ 'node_use_dtrace=="false" and node_use_etw=="false"', {
               'inputs': [ 'src/notrace_macros.py' ]
             }],
+            ['node_use_lttng=="false"', {
+              'inputs': [ 'src/nolttng_macros.py' ]
+            }],
             [ 'node_use_perfctr=="false"', {
               'inputs': [ 'src/perfctr_macros.py' ]
             }]
index 4386d37..fd65fbf 100644 (file)
 #include "node_dtrace.h"
 #endif
 
+#if defined HAVE_LTTNG
+#include "node_lttng.h"
+#endif
+
 #include "ares.h"
 #include "async-wrap.h"
 #include "async-wrap-inl.h"
@@ -2871,6 +2875,10 @@ void LoadEnvironment(Environment* env) {
   InitDTrace(env, global);
 #endif
 
+#if defined HAVE_LTTNG
+  InitLTTNG(env, global);
+#endif
+
 #if defined HAVE_PERFCTR
   InitPerfCounters(env, global);
 #endif
diff --git a/src/node_lttng.cc b/src/node_lttng.cc
new file mode 100644 (file)
index 0000000..0c63882
--- /dev/null
@@ -0,0 +1,266 @@
+#include "util.h"
+
+#ifdef HAVE_LTTNG
+#include "node_lttng.h"
+#include "node_lttng_provider.h"
+#include <string.h>
+#else
+#define NODE_HTTP_SERVER_REQUEST(arg0, arg1)
+#define NODE_HTTP_SERVER_REQUEST_ENABLED() (0)
+#define NODE_HTTP_SERVER_RESPONSE(arg0)
+#define NODE_HTTP_SERVER_RESPONSE_ENABLED() (0)
+#define NODE_HTTP_CLIENT_REQUEST(arg0, arg1)
+#define NODE_HTTP_CLIENT_REQUEST_ENABLED() (0)
+#define NODE_HTTP_CLIENT_RESPONSE(arg0)
+#define NODE_HTTP_CLIENT_RESPONSE_ENABLED() (0)
+#define NODE_NET_SERVER_CONNECTION(arg0)
+#define NODE_NET_SERVER_CONNECTION_ENABLED() (0)
+#define NODE_NET_STREAM_END(arg0)
+#define NODE_NET_STREAM_END_ENABLED() (0)
+#define NODE_GC_START(arg0, arg1, arg2)
+#define NODE_GC_DONE(arg0, arg1, arg2)
+#endif
+
+#include "env.h"
+#include "env-inl.h"
+
+namespace node {
+
+using v8::FunctionCallbackInfo;
+using v8::FunctionTemplate;
+using v8::GCCallbackFlags;
+using v8::GCEpilogueCallback;
+using v8::GCPrologueCallback;
+using v8::GCType;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Isolate;
+using v8::Local;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+#define SLURP_STRING(obj, member, valp) \
+  if (!(obj)->IsObject()) { \
+    return env->ThrowError( \
+        "expected object for " #obj " to contain string member " #member); \
+  } \
+  node::Utf8Value _##member(env->isolate(), \
+      obj->Get(OneByteString(env->isolate(), #member))); \
+  if ((*(const char **)valp = *_##member) == nullptr) \
+    *(const char **)valp = "<unknown>";
+
+#define SLURP_INT(obj, member, valp) \
+  if (!(obj)->IsObject()) { \
+    return env->ThrowError( \
+      "expected object for " #obj " to contain integer member " #member); \
+  } \
+  *valp = obj->Get(OneByteString(env->isolate(), #member)) \
+      ->ToInteger(env->isolate())->Value();
+
+#define SLURP_OBJECT(obj, member, valp) \
+  if (!(obj)->IsObject()) { \
+    return env->ThrowError( \
+      "expected object for " #obj " to contain object member " #member); \
+  } \
+  *valp = Local<Object>::Cast(obj->Get(OneByteString(env->isolate(), #member)));
+
+#define SLURP_CONNECTION(arg, conn) \
+  if (!(arg)->IsObject()) { \
+    return env->ThrowError( \
+      "expected argument " #arg " to be a connection object"); \
+  } \
+  node_lttng_connection_t conn; \
+  Local<Object> _##conn = Local<Object>::Cast(arg); \
+  Local<Value> _handle = \
+      (_##conn)->Get(FIXED_ONE_BYTE_STRING(env->isolate(), "_handle")); \
+  if (_handle->IsObject()) { \
+    SLURP_INT(_handle.As<Object>(), fd, &conn.fd); \
+  } else { \
+    conn.fd = -1; \
+  } \
+  SLURP_STRING(_##conn, remoteAddress, &conn.remote); \
+  SLURP_INT(_##conn, remotePort, &conn.port); \
+  SLURP_INT(_##conn, bufferSize, &conn.buffered);
+
+#define SLURP_CONNECTION_HTTP_CLIENT(arg, conn) \
+  if (!(arg)->IsObject()) { \
+    return env->ThrowError( \
+      "expected argument " #arg " to be a connection object"); \
+  } \
+  node_lttng_connection_t conn; \
+  Local<Object> _##conn = Local<Object>::Cast(arg); \
+  SLURP_INT(_##conn, fd, &conn.fd); \
+  SLURP_STRING(_##conn, host, &conn.remote); \
+  SLURP_INT(_##conn, port, &conn.port); \
+  SLURP_INT(_##conn, bufferSize, &conn.buffered);
+
+#define SLURP_CONNECTION_HTTP_CLIENT_RESPONSE(arg0, arg1, conn) \
+  if (!(arg0)->IsObject()) { \
+    return env->ThrowError( \
+      "expected argument " #arg0 " to be a connection object"); \
+  } \
+  if (!(arg1)->IsObject()) { \
+    return env->ThrowError( \
+      "expected argument " #arg1 " to be a connection object"); \
+  } \
+  node_lttng_connection_t conn; \
+  Local<Object> _##conn = Local<Object>::Cast(arg0); \
+  SLURP_INT(_##conn, fd, &conn.fd); \
+  SLURP_INT(_##conn, bufferSize, &conn.buffered); \
+  _##conn = Local<Object>::Cast(arg1); \
+  SLURP_STRING(_##conn, host, &conn.remote); \
+  SLURP_INT(_##conn, port, &conn.port);
+
+
+void LTTNG_NET_SERVER_CONNECTION(const FunctionCallbackInfo<Value>& args) {
+  if (!NODE_NET_SERVER_CONNECTION_ENABLED())
+    return;
+  Environment* env = Environment::GetCurrent(args);
+  SLURP_CONNECTION(args[0], conn);
+  NODE_NET_SERVER_CONNECTION(&conn, conn.remote, conn.port, conn.fd);
+}
+
+
+void LTTNG_NET_STREAM_END(const FunctionCallbackInfo<Value>& args) {
+  if (!NODE_NET_STREAM_END_ENABLED())
+    return;
+  Environment* env = Environment::GetCurrent(args);
+  SLURP_CONNECTION(args[0], conn);
+  NODE_NET_STREAM_END(&conn, conn.remote, conn.port, conn.fd);
+}
+
+
+void LTTNG_HTTP_SERVER_REQUEST(const FunctionCallbackInfo<Value>& args) {
+  node_lttng_http_server_request_t req;
+
+  if (!NODE_HTTP_SERVER_REQUEST_ENABLED())
+    return;
+
+  if (!args[0]->IsObject())
+    return;
+
+  Environment* env = Environment::GetCurrent(args);
+  Local<Object> arg0 = args[0].As<Object>();
+  Local<Object> headers;
+
+  memset(&req, 0, sizeof(req));
+  req._un.version = 1;
+  SLURP_STRING(arg0, url, &req.url);
+  SLURP_STRING(arg0, method, &req.method);
+  SLURP_OBJECT(arg0, headers, &headers);
+
+  if (!(headers)->IsObject()) {
+    return env->ThrowError(
+      "expected object for request to contain string member headers");
+  }
+
+  Local<Value> strfwdfor = headers->Get(env->x_forwarded_string());
+  node::Utf8Value fwdfor(env->isolate(), strfwdfor);
+  req.forwarded_for = *fwdfor;
+
+  if (!strfwdfor->IsString() || req.forwarded_for == nullptr)
+    req.forwarded_for = "";
+
+  SLURP_CONNECTION(args[1], conn);
+  NODE_HTTP_SERVER_REQUEST(&req, &conn, conn.remote, conn.port, req.method, \
+                           req.url, conn.fd);
+}
+
+
+void LTTNG_HTTP_SERVER_RESPONSE(const FunctionCallbackInfo<Value>& args) {
+  if (!NODE_HTTP_SERVER_RESPONSE_ENABLED())
+    return;
+  Environment* env = Environment::GetCurrent(args);
+  SLURP_CONNECTION(args[0], conn);
+  NODE_HTTP_SERVER_RESPONSE(&conn, conn.remote, conn.port, conn.fd);
+}
+
+
+void LTTNG_HTTP_CLIENT_REQUEST(const FunctionCallbackInfo<Value>& args) {
+  node_lttng_http_client_request_t req;
+  char* header;
+
+  if (!NODE_HTTP_CLIENT_REQUEST_ENABLED())
+    return;
+
+  Environment* env = Environment::GetCurrent(args);
+
+  /*
+   * For the method and URL, we're going to dig them out of the header.  This
+   * is not as efficient as it could be, but we would rather not force the
+   * caller here to retain their method and URL until the time at which
+   * LTTNG_HTTP_CLIENT_REQUEST can be called.
+   */
+  Local<Object> arg0 = args[0].As<Object>();
+  SLURP_STRING(arg0, _header, &header);
+
+  req.method = header;
+
+  while (*header != '\0' && *header != ' ')
+    header++;
+
+  if (*header != '\0')
+    *header++ = '\0';
+
+  req.url = header;
+
+  while (*header != '\0' && *header != ' ')
+    header++;
+
+  *header = '\0';
+
+  SLURP_CONNECTION_HTTP_CLIENT(args[1], conn);
+  NODE_HTTP_CLIENT_REQUEST(&req, &conn, conn.remote, conn.port, req.method, \
+                           req.url, conn.fd);
+}
+
+
+void LTTNG_HTTP_CLIENT_RESPONSE(const FunctionCallbackInfo<Value>& args) {
+  if (!NODE_HTTP_CLIENT_RESPONSE_ENABLED())
+    return;
+  Environment* env = Environment::GetCurrent(args);
+  SLURP_CONNECTION_HTTP_CLIENT_RESPONSE(args[0], args[1], conn);
+  NODE_HTTP_CLIENT_RESPONSE(&conn, conn.remote, conn.port, conn.fd);
+}
+
+
+void lttng_gc_start(Isolate* isolate, GCType type, GCCallbackFlags flags) {
+  NODE_GC_START(type, flags, isolate);
+}
+
+
+void lttng_gc_done(Isolate* isolate, GCType type, GCCallbackFlags flags) {
+  NODE_GC_DONE(type, flags, isolate);
+}
+
+void InitLTTNG(Environment* env, Handle<Object> target) {
+  HandleScope scope(env->isolate());
+
+  static struct {
+    const char *name;
+    void (*func)(const FunctionCallbackInfo<Value>&);
+  } tab[] = {
+#define NODE_PROBE(name) #name, name
+    { NODE_PROBE(LTTNG_NET_SERVER_CONNECTION) },
+    { NODE_PROBE(LTTNG_NET_STREAM_END) },
+    { NODE_PROBE(LTTNG_HTTP_SERVER_REQUEST) },
+    { NODE_PROBE(LTTNG_HTTP_SERVER_RESPONSE) },
+    { NODE_PROBE(LTTNG_HTTP_CLIENT_REQUEST) },
+    { NODE_PROBE(LTTNG_HTTP_CLIENT_RESPONSE) }
+#undef NODE_PROBE
+  };
+
+  for (unsigned int i = 0; i < ARRAY_SIZE(tab); i++) {
+    Local<String> key = OneByteString(env->isolate(), tab[i].name);
+    Local<Value> val = env->NewFunctionTemplate(tab[i].func)->GetFunction();
+    target->Set(key, val);
+  }
+
+#if defined HAVE_LTTNG
+  env->isolate()->AddGCPrologueCallback(lttng_gc_start);
+  env->isolate()->AddGCEpilogueCallback(lttng_gc_done);
+#endif
+}
+
+}  // namespace node
diff --git a/src/node_lttng.h b/src/node_lttng.h
new file mode 100644 (file)
index 0000000..31f706f
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef SRC_NODE_LTTNG_H_
+#define SRC_NODE_LTTNG_H_
+
+#include "node.h"
+#include "v8.h"
+#include "env.h"
+
+extern "C" {
+typedef struct {
+  int32_t fd;
+  int32_t port;
+  const char* remote;
+  int32_t buffered;
+} node_lttng_connection_t;
+
+typedef struct {
+  const char* url;
+  const char* method;
+} node_lttng_http_client_request_t;
+
+typedef struct {
+  union {
+    uint32_t version;
+    uintptr_t unused;  /* for compat. with old 64-bit struct */
+  } _un;
+  const char* url;
+  const char* method;
+  const char* forwarded_for;
+  const char* _pad[8];
+} node_lttng_http_server_request_t;
+
+}  // extern "C"
+
+namespace node {
+
+void InitLTTNG(Environment* env, v8::Handle<v8::Object> target);
+
+}  // namespace node
+
+#endif  // SRC_NODE_LTTNG_H_
diff --git a/src/node_lttng_provider.h b/src/node_lttng_provider.h
new file mode 100644 (file)
index 0000000..22dd935
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef SRC_NODE_LTTNG_PROVIDER_H_
+#define SRC_NODE_LTTNG_PROVIDER_H_
+
+#define TRACEPOINT_CREATE_PROBES
+#define TRACEPOINT_DEFINE
+#include "node_lttng_tp.h"
+
+namespace node {
+
+void NODE_HTTP_SERVER_REQUEST(node_lttng_http_server_request_t* req,
+                              node_lttng_connection_t* conn,
+                              const char *remote, int port,
+                              const char *method, const char *url,
+                              int fd) {
+  tracepoint(node, http_server_request, req->url, req->method, \
+             req->forwarded_for);
+}
+
+void NODE_HTTP_SERVER_RESPONSE(node_lttng_connection_t* conn,
+                              const char *remote, int port, int fd) {
+  tracepoint(node, http_server_response, port, conn->remote, fd);
+}
+
+void NODE_HTTP_CLIENT_REQUEST(node_lttng_http_client_request_t* req,
+                              node_lttng_connection_t* conn,
+                              const char *remote, int port,
+                              const char *method, const char *url,
+                              int fd) {
+  tracepoint(node, http_client_request, req->url, req->method);
+}
+
+void NODE_HTTP_CLIENT_RESPONSE(node_lttng_connection_t* conn,
+                               const char *remote, int port, int fd) {
+  tracepoint(node, http_client_response, port, conn->remote, fd);
+}
+
+void NODE_NET_SERVER_CONNECTION(node_lttng_connection_t* conn,
+                                const char *remote, int port, int fd) {
+  tracepoint(node, net_server_connection, conn->remote, port, fd, \
+             conn->buffered);
+}
+
+void NODE_NET_STREAM_END(node_lttng_connection_t* conn,
+                        const char *remote, int port, int fd) {
+  tracepoint(node, net_stream_end, conn->remote, port, fd);
+}
+
+void NODE_GC_START(v8::GCType type,
+                   v8::GCCallbackFlags flags,
+                   v8::Isolate* isolate) {
+  const char* typeStr = "";
+  const char* flagsStr = "";
+  if (type == v8::GCType::kGCTypeScavenge) {
+    typeStr = "kGCTypeScavenge";
+  } else if (type == v8::GCType::kGCTypeMarkSweepCompact) {
+    typeStr = "kGCTypeMarkSweepCompact";
+  } else if (type == v8::GCType::kGCTypeAll) {
+    typeStr = "kGCTypeAll";
+  }
+  if (flags == v8::GCCallbackFlags::kNoGCCallbackFlags) {
+    flagsStr = "kNoGCCallbackFlags";
+  } else if (flags == v8::GCCallbackFlags::kGCCallbackFlagCompacted) {
+    flagsStr = "kGCCallbackFlagCompacted";
+  }
+
+  tracepoint(node, gc_start, typeStr, flagsStr);
+}
+
+
+void NODE_GC_DONE(v8::GCType type,
+                  v8::GCCallbackFlags flags,
+                  v8::Isolate* isolate) {
+  const char* typeStr = "";
+  const char* flagsStr = "";
+  if (type == v8::GCType::kGCTypeScavenge) {
+    typeStr = "kGCTypeScavenge";
+  } else if (type == v8::GCType::kGCTypeMarkSweepCompact) {
+    typeStr = "kGCTypeMarkSweepCompact";
+  } else if (type == v8::GCType::kGCTypeAll) {
+    typeStr = "kGCTypeAll";
+  }
+  if (flags == v8::GCCallbackFlags::kNoGCCallbackFlags) {
+    flagsStr = "kNoGCCallbackFlags";
+  } else if (flags == v8::GCCallbackFlags::kGCCallbackFlagCompacted) {
+    flagsStr = "kGCCallbackFlagCompacted";
+  }
+
+  tracepoint(node, gc_done, typeStr, flagsStr);
+}
+
+bool NODE_HTTP_SERVER_REQUEST_ENABLED() { return true; }
+bool NODE_HTTP_SERVER_RESPONSE_ENABLED() { return true; }
+bool NODE_HTTP_CLIENT_REQUEST_ENABLED() { return true; }
+bool NODE_HTTP_CLIENT_RESPONSE_ENABLED() { return true; }
+bool NODE_NET_SERVER_CONNECTION_ENABLED() { return true; }
+bool NODE_NET_STREAM_END_ENABLED() { return true; }
+
+}  // namespace node
+
+#endif  // SRC_NODE_LTTNG_PROVIDER_H_
diff --git a/src/node_lttng_tp.h b/src/node_lttng_tp.h
new file mode 100644 (file)
index 0000000..53d04f4
--- /dev/null
@@ -0,0 +1,130 @@
+#undef TRACEPOINT_PROVIDER
+#define TRACEPOINT_PROVIDER node
+
+#undef TRACEPOINT_INCLUDE
+#define TRACEPOINT_INCLUDE "./node_lttng_tp.h"
+
+#if !defined(__NODE_LTTNG_TP_H) || defined(TRACEPOINT_HEADER_MULTI_READ)
+#define __NODE_LTTNG_TP_H
+
+#include <lttng/tracepoint.h>
+
+TRACEPOINT_EVENT(
+  node,
+  http_server_request,
+  TP_ARGS(
+    const char*, url,
+    const char*, method,
+    const char*, forwardedFor
+  ),
+  TP_FIELDS(
+    ctf_string(url, url)
+    ctf_string(method, method)
+    ctf_string(forwardedFor, forwardedFor)
+  )
+)
+
+TRACEPOINT_EVENT(
+  node,
+  http_server_response,
+  TP_ARGS(
+    int, port,
+    const char*, remote,
+    int, fd
+  ),
+  TP_FIELDS(
+    ctf_integer(int, port, port)
+    ctf_string(remote, remote)
+    ctf_integer(int, fd, fd)
+  )
+)
+
+TRACEPOINT_EVENT(
+  node,
+  http_client_request,
+  TP_ARGS(
+    const char*, url,
+    const char*, method
+  ),
+  TP_FIELDS(
+    ctf_string(url, url)
+    ctf_string(method, method)
+  )
+)
+
+TRACEPOINT_EVENT(
+  node,
+  http_client_response,
+  TP_ARGS(
+    int, port,
+    const char*, remote,
+    int, fd
+  ),
+  TP_FIELDS(
+    ctf_integer(int, port, port)
+    ctf_string(remote, remote)
+    ctf_integer(int, fd, fd)
+  )
+)
+
+TRACEPOINT_EVENT(
+  node,
+  net_server_connection,
+  TP_ARGS(
+    const char*, remote,
+    int, port,
+    int, fd,
+    int, buffered
+  ),
+  TP_FIELDS(
+    ctf_string(remote, remote)
+    ctf_integer(int, port, port)
+    ctf_integer(int, fd, fd)
+    ctf_integer(int, buffered, buffered)
+  )
+)
+
+TRACEPOINT_EVENT(
+  node,
+  net_stream_end,
+  TP_ARGS(
+    const char*, remote,
+    int, port,
+    int, fd
+  ),
+  TP_FIELDS(
+    ctf_string(remote, remote)
+    ctf_integer(int, port, port)
+    ctf_integer(int, fd, fd)
+  )
+)
+
+TRACEPOINT_EVENT(
+  node,
+  gc_start,
+  TP_ARGS(
+    const char*, gctype,
+    const char*, gcflags
+  ),
+  TP_FIELDS(
+    ctf_string(gctype, gctype)
+    ctf_string(gcflags, gcflags)
+  )
+)
+
+TRACEPOINT_EVENT(
+  node,
+  gc_done,
+  TP_ARGS(
+    const char*, gctype,
+    const char*, gcflags
+  ),
+  TP_FIELDS(
+    ctf_string(gctype, gctype)
+    ctf_string(gcflags, gcflags)
+  )
+)
+
+#endif /* __NODE_LTTNG_TP_H */
+
+#include <lttng/tracepoint-event.h>
diff --git a/src/nolttng_macros.py b/src/nolttng_macros.py
new file mode 100644 (file)
index 0000000..cefd805
--- /dev/null
@@ -0,0 +1,9 @@
+# This file is used by tools/js2c.py to preprocess out the LTTNG symbols in
+# builds that don't support LTTNG. This is not used in builds that support
+# LTTNG.
+macro LTTNG_HTTP_CLIENT_REQUEST(x) = ;
+macro LTTNG_HTTP_CLIENT_RESPONSE(x) = ;
+macro LTTNG_HTTP_SERVER_REQUEST(x) = ;
+macro LTTNG_HTTP_SERVER_RESPONSE(x) = ;
+macro LTTNG_NET_SERVER_CONNECTION(x) = ;
+macro LTTNG_NET_STREAM_END(x) = ;
index 1599de0..352f7b6 100644 (file)
@@ -170,6 +170,15 @@ if (global.COUNTER_NET_SERVER_CONNECTION) {
   knownGlobals.push(COUNTER_HTTP_CLIENT_RESPONSE);
 }
 
+if (global.LTTNG_HTTP_SERVER_RESPONSE) {
+  knownGlobals.push(LTTNG_HTTP_SERVER_RESPONSE);
+  knownGlobals.push(LTTNG_HTTP_SERVER_REQUEST);
+  knownGlobals.push(LTTNG_HTTP_CLIENT_RESPONSE);
+  knownGlobals.push(LTTNG_HTTP_CLIENT_REQUEST);
+  knownGlobals.push(LTTNG_NET_STREAM_END);
+  knownGlobals.push(LTTNG_NET_SERVER_CONNECTION);
+}
+
 if (global.ArrayBuffer) {
   knownGlobals.push(ArrayBuffer);
   knownGlobals.push(Int8Array);
index e6e4cbb..1af9a77 100644 (file)
@@ -26,7 +26,12 @@ function test(environ, shouldWrite) {
 
   var spawn = require('child_process').spawn;
   var child = spawn(process.execPath, [__filename, 'child'], {
-    env: { NODE_DEBUG: environ }
+    // Lttng requires the HOME env variable or it prints to stderr,
+    // This is not really ideal, as it breaks this test, so the HOME
+    // env variable is passed to the child to make the test pass.
+    // this is fixed in the next version of lttng (2.7+), so we can
+    // remove it at sometime in the future.
+    env: { NODE_DEBUG: environ, HOME: process.env.HOME }
   });
 
   expectErr = expectErr.split('%PID%').join(child.pid);