summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlen Keane <glenkeane.94@gmail.com>2015-01-22 12:35:16 +0000
committerBen Noordhuis <info@bnoordhuis.nl>2015-02-09 18:06:57 +0100
commit5e825d1073b57a87fc9a77751ed3e21c86970082 (patch)
tree1236727442096918822cbf47516c43ec15264889
parentb677b844fc1de328a0f2b0151bdfc045cb5d0c81 (diff)
downloadnodejs-5e825d1073b57a87fc9a77751ed3e21c86970082.tar.gz
nodejs-5e825d1073b57a87fc9a77751ed3e21c86970082.tar.bz2
nodejs-5e825d1073b57a87fc9a77751ed3e21c86970082.zip
tracing: add lttng support for tracing on linux
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>
-rw-r--r--Makefile3
-rwxr-xr-xconfigure14
-rw-r--r--lib/_http_client.js2
-rw-r--r--lib/_http_server.js2
-rw-r--r--lib/net.js2
-rw-r--r--node.gyp12
-rw-r--r--src/node.cc8
-rw-r--r--src/node_lttng.cc266
-rw-r--r--src/node_lttng.h40
-rw-r--r--src/node_lttng_provider.h100
-rw-r--r--src/node_lttng_tp.h130
-rw-r--r--src/nolttng_macros.py9
-rw-r--r--test/common.js9
-rw-r--r--test/sequential/test-util-debug.js7
14 files changed, 602 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index fdbf4d717..39741096f 100644
--- 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
diff --git a/configure b/configure
index e85621e9c..d63232626 100755
--- 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':
diff --git a/lib/_http_client.js b/lib/_http_client.js
index 6804157ee..b02ab66b2 100644
--- a/lib/_http_client.js
+++ b/lib/_http_client.js
@@ -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;
diff --git a/lib/_http_server.js b/lib/_http_server.js
index d8b979943..99903024c 100644
--- a/lib/_http_server.js
+++ b/lib/_http_server.js
@@ -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) {
diff --git a/lib/net.js b/lib/net.js
index af8c3dd8f..030083d3f 100644
--- a/lib/net.js
+++ b/lib/net.js
@@ -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);
}
diff --git a/node.gyp b/node.gyp
index 2874f1309..8506b2868 100644
--- 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',
@@ -260,6 +261,14 @@
}
] ]
} ],
+ [ '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)' ],
@@ -450,6 +459,9 @@
[ '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' ]
}]
diff --git a/src/node.cc b/src/node.cc
index 4386d372b..fd65fbff0 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -23,6 +23,10 @@
#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
index 000000000..0c63882c7
--- /dev/null
+++ b/src/node_lttng.cc
@@ -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
index 000000000..31f706f75
--- /dev/null
+++ b/src/node_lttng.h
@@ -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
index 000000000..22dd935a9
--- /dev/null
+++ b/src/node_lttng_provider.h
@@ -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
index 000000000..53d04f47a
--- /dev/null
+++ b/src/node_lttng_tp.h
@@ -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
index 000000000..cefd80507
--- /dev/null
+++ b/src/nolttng_macros.py
@@ -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) = ;
diff --git a/test/common.js b/test/common.js
index 1599de07b..352f7b676 100644
--- a/test/common.js
+++ b/test/common.js
@@ -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);
diff --git a/test/sequential/test-util-debug.js b/test/sequential/test-util-debug.js
index e6e4cbb5a..1af9a7705 100644
--- a/test/sequential/test-util-debug.js
+++ b/test/sequential/test-util-debug.js
@@ -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);