From 6ab942b055b4f70303139b272763297896150536 Mon Sep 17 00:00:00 2001 From: GLEN Date: Thu, 22 Jan 2015 12:35:16 +0000 Subject: [PATCH 1/5] 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. --- Makefile | 3 +- configure | 14 ++ lib/_http_client.js | 2 + lib/_http_server.js | 2 + lib/net.js | 2 + node.gyp | 12 ++ src/node.cc | 8 + src/node_lttng.cc | 264 +++++++++++++++++++++++++++++ src/node_lttng.h | 40 +++++ src/node_lttng_provider.h | 100 +++++++++++ src/node_lttng_tp.h | 131 ++++++++++++++ src/nolttng_macros.py | 10 ++ test/common.js | 9 + test/sequential/test-util-debug.js | 2 +- 14 files changed, 597 insertions(+), 2 deletions(-) create mode 100644 src/node_lttng.cc create mode 100644 src/node_lttng.h create mode 100644 src/node_lttng_provider.h create mode 100644 src/node_lttng_tp.h create mode 100644 src/nolttng_macros.py diff --git a/Makefile b/Makefile index ffaed7b0338ebd..a920dcbae79e71 100644 --- a/Makefile +++ b/Makefile @@ -395,8 +395,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 e85621e9cb4af0..d63232626c7d1e 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 6804157ee0a4dc..b02ab66b294d13 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 d8b979943841e1..99903024c26d14 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 af8c3dd8feb68e..030083d3f40983 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 d58ec25dcb3c7c..7d7f84756dcb1f 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 7c9032bf02945b..40af3009b1fd28 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 00000000000000..66f25ec5a95f61 --- /dev/null +++ b/src/node_lttng.cc @@ -0,0 +1,264 @@ +#include "util.h" + +#ifdef HAVE_LTTNG +#include "node_lttng.h" +#include "node_lttng_provider.h" +#include +#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 = ""; + +#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::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 _##conn = Local::Cast(arg); \ + Local _handle = \ + (_##conn)->Get(FIXED_ONE_BYTE_STRING(env->isolate(), "_handle")); \ + if (_handle->IsObject()) { \ + SLURP_INT(_handle.As(), 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 _##conn = Local::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 _##conn = Local::Cast(arg0); \ + SLURP_INT(_##conn, fd, &conn.fd); \ + SLURP_INT(_##conn, bufferSize, &conn.buffered); \ + _##conn = Local::Cast(arg1); \ + SLURP_STRING(_##conn, host, &conn.remote); \ + SLURP_INT(_##conn, port, &conn.port); + + +void LTTNG_NET_SERVER_CONNECTION(const FunctionCallbackInfo& 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& 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& args) { + node_lttng_http_server_request_t req; + + if (!NODE_HTTP_SERVER_REQUEST_ENABLED()) + return; + + Environment* env = Environment::GetCurrent(args); + HandleScope scope(env->isolate()); + Local arg0 = Local::Cast(args[0]); + Local 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 strfwdfor = headers->Get(env->x_forwarded_string()); + node::Utf8Value fwdfor(env->isolate(), strfwdfor); + + if (!strfwdfor->IsString() || (req.forwardedFor = *fwdfor) == nullptr) + req.forwardedFor = const_cast(""); + + 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& 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& args) { + node_lttng_http_client_request_t req; + char *header; + + if (!NODE_HTTP_CLIENT_REQUEST_ENABLED()) + return; + + Environment* env = Environment::GetCurrent(args); + HandleScope scope(env->isolate()); + + /* + * 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 arg0 = Local::Cast(args[0]); + 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& 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 target) { + HandleScope scope(env->isolate()); + + static struct { + const char *name; + void (*func)(const FunctionCallbackInfo&); + } 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 key = OneByteString(env->isolate(), tab[i].name); + Local 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 00000000000000..76bf799a1fefb8 --- /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; + char* remote; + int32_t buffered; +} node_lttng_connection_t; + +typedef struct { + char* url; + 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; + char* url; + char* method; + char* forwardedFor; + char* _pad[8]; +} node_lttng_http_server_request_t; + +} // extern "C" + +namespace node { + +void InitLTTNG(Environment* env, v8::Handle 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 00000000000000..d86b4445eec0f9 --- /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->forwardedFor); +} + +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) { + int opt1 = 1 << 0; + int opt2 = 1 << 1; + char* typeStr = ""; + char* flagsStr = ""; + if (type == opt1) { + typeStr = "kGCTypeScavenge"; + } else if (type == opt2) { + typeStr = "kGCTypeMarkSweepCompact"; + } else { + typeStr = "kGCTypeAll"; + } + if (flags == opt1) { + flagsStr = "kNoGCCallbackFlags"; + } else { + flagsStr = "kGCCallbackFlagCompacted"; + } + + tracepoint(node, gc_start, typeStr, flagsStr); +} + + +void NODE_GC_DONE(v8::GCType type, + v8::GCCallbackFlags flags, + v8::Isolate* isolate) { + int opt1 = 1 << 0; + int opt2 = 1 << 1; + char* typeStr = ""; + char* flagsStr = ""; + if (type == opt1) { + typeStr = "kGCTypeScavenge"; + } else if (type == opt2) { + typeStr = "kGCTypeMarkSweepCompact"; + } else { + typeStr = "kGCTypeAll"; + } + if (flags == opt1) { + flagsStr = "kNoGCCallbackFlags"; + } else { + 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 00000000000000..c10b68807b2ba2 --- /dev/null +++ b/src/node_lttng_tp.h @@ -0,0 +1,131 @@ +#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 + +TRACEPOINT_EVENT( + node, + http_server_request, + TP_ARGS( + char*, url, + char*, method, + 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, + 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( + char*, url, + char*, method + ), + TP_FIELDS( + ctf_string(url, url) + ctf_string(method, method) + ) +) + +// DBTODO - sort out BYTE_ORDER issue with ints +TRACEPOINT_EVENT( + node, + http_client_response, + TP_ARGS( + int, port, + 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( + 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( + 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( + char*, gctype, + char*, gcflags + ), + TP_FIELDS( + ctf_string(gctype, gctype) + ctf_string(gcflags, gcflags) + ) +) + +TRACEPOINT_EVENT( + node, + gc_done, + TP_ARGS( + char*, gctype, + char*, gcflags + ), + TP_FIELDS( + ctf_string(gctype, gctype) + ctf_string(gcflags, gcflags) + ) +) + +#endif /* __NODE_LTTNG_TP_H */ + +#include diff --git a/src/nolttng_macros.py b/src/nolttng_macros.py new file mode 100644 index 00000000000000..a11ccc77bd5e33 --- /dev/null +++ b/src/nolttng_macros.py @@ -0,0 +1,10 @@ +# 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 b682a46c324b81..e9a38a6b4efc74 100644 --- a/test/common.js +++ b/test/common.js @@ -152,6 +152,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 e6e4cbb5a5f806..4994bd05eda7ed 100644 --- a/test/sequential/test-util-debug.js +++ b/test/sequential/test-util-debug.js @@ -26,7 +26,7 @@ function test(environ, shouldWrite) { var spawn = require('child_process').spawn; var child = spawn(process.execPath, [__filename, 'child'], { - env: { NODE_DEBUG: environ } + env: { NODE_DEBUG: environ, HOME: process.env.HOME } }); expectErr = expectErr.split('%PID%').join(child.pid); From 71c0ab7c600b0138ede66380cb2c58723cb84a7b Mon Sep 17 00:00:00 2001 From: Glen Keane Date: Fri, 6 Feb 2015 12:14:53 +0000 Subject: [PATCH 2/5] Fixing nits --- src/node_lttng.cc | 10 +++-- src/node_lttng_provider.h | 64 +++++++++++++++--------------- src/node_lttng_tp.h | 8 ++-- test/sequential/test-util-debug.js | 5 +++ 4 files changed, 47 insertions(+), 40 deletions(-) diff --git a/src/node_lttng.cc b/src/node_lttng.cc index 66f25ec5a95f61..7369dd47441cb7 100644 --- a/src/node_lttng.cc +++ b/src/node_lttng.cc @@ -137,8 +137,10 @@ void LTTNG_HTTP_SERVER_REQUEST(const FunctionCallbackInfo& args) { if (!NODE_HTTP_SERVER_REQUEST_ENABLED()) return; + if (!args[0]->IsObject()) + return; + Environment* env = Environment::GetCurrent(args); - HandleScope scope(env->isolate()); Local arg0 = Local::Cast(args[0]); Local headers; @@ -155,8 +157,9 @@ void LTTNG_HTTP_SERVER_REQUEST(const FunctionCallbackInfo& args) { Local strfwdfor = headers->Get(env->x_forwarded_string()); node::Utf8Value fwdfor(env->isolate(), strfwdfor); + req.forwardedFor = *fwdfor; - if (!strfwdfor->IsString() || (req.forwardedFor = *fwdfor) == nullptr) + if (!strfwdfor->IsString() || req.forwardedFor == nullptr) req.forwardedFor = const_cast(""); SLURP_CONNECTION(args[1], conn); @@ -176,13 +179,12 @@ void LTTNG_HTTP_SERVER_RESPONSE(const FunctionCallbackInfo& args) { void LTTNG_HTTP_CLIENT_REQUEST(const FunctionCallbackInfo& args) { node_lttng_http_client_request_t req; - char *header; + char* header; if (!NODE_HTTP_CLIENT_REQUEST_ENABLED()) return; Environment* env = Environment::GetCurrent(args); - HandleScope scope(env->isolate()); /* * For the method and URL, we're going to dig them out of the header. This diff --git a/src/node_lttng_provider.h b/src/node_lttng_provider.h index d86b4445eec0f9..88c1f7126ce47d 100644 --- a/src/node_lttng_provider.h +++ b/src/node_lttng_provider.h @@ -8,56 +8,58 @@ 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->forwardedFor); + 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->forwardedFor); } void NODE_HTTP_SERVER_RESPONSE(node_lttng_connection_t* conn, - const char *remote, int port, int fd) { + 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) { + 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) { + 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); + 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) { + 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) { - int opt1 = 1 << 0; - int opt2 = 1 << 1; - char* typeStr = ""; - char* flagsStr = ""; - if (type == opt1) { - typeStr = "kGCTypeScavenge"; - } else if (type == opt2) { + const char* typeStr = ""; + const char* flagsStr = ""; + if (type == v8::GCType::kGCTypeScavenge) { + typeStr = "kGCTypeScavenge"; + } else if (type == v8::GCType::kGCTypeMarkSweepCompact) { typeStr = "kGCTypeMarkSweepCompact"; - } else { + } else if (type == v8::GCType::kGCTypeAll) { typeStr = "kGCTypeAll"; } - if (flags == opt1) { + if (flags == v8::GCCallbackFlags::kNoGCCallbackFlags) { flagsStr = "kNoGCCallbackFlags"; - } else { + } else if (flags == v8::GCCallbackFlags::kGCCallbackFlagCompacted) { flagsStr = "kGCCallbackFlagCompacted"; } @@ -68,20 +70,18 @@ void NODE_GC_START(v8::GCType type, void NODE_GC_DONE(v8::GCType type, v8::GCCallbackFlags flags, v8::Isolate* isolate) { - int opt1 = 1 << 0; - int opt2 = 1 << 1; - char* typeStr = ""; - char* flagsStr = ""; - if (type == opt1) { - typeStr = "kGCTypeScavenge"; - } else if (type == opt2) { + const char* typeStr = ""; + const char* flagsStr = ""; + if (type == v8::GCType::kGCTypeScavenge) { + typeStr = "kGCTypeScavenge"; + } else if (type == v8::GCType::kGCTypeMarkSweepCompact) { typeStr = "kGCTypeMarkSweepCompact"; - } else { + } else if (type == v8::GCType::kGCTypeAll) { typeStr = "kGCTypeAll"; } - if (flags == opt1) { + if (flags == v8::GCCallbackFlags::kNoGCCallbackFlags) { flagsStr = "kNoGCCallbackFlags"; - } else { + } else if (flags == v8::GCCallbackFlags::kGCCallbackFlagCompacted) { flagsStr = "kGCCallbackFlagCompacted"; } diff --git a/src/node_lttng_tp.h b/src/node_lttng_tp.h index c10b68807b2ba2..6925ed3e0ad8ff 100644 --- a/src/node_lttng_tp.h +++ b/src/node_lttng_tp.h @@ -104,8 +104,8 @@ TRACEPOINT_EVENT( node, gc_start, TP_ARGS( - char*, gctype, - char*, gcflags + const char*, gctype, + const char*, gcflags ), TP_FIELDS( ctf_string(gctype, gctype) @@ -117,8 +117,8 @@ TRACEPOINT_EVENT( node, gc_done, TP_ARGS( - char*, gctype, - char*, gcflags + const char*, gctype, + const char*, gcflags ), TP_FIELDS( ctf_string(gctype, gctype) diff --git a/test/sequential/test-util-debug.js b/test/sequential/test-util-debug.js index 4994bd05eda7ed..3319ca485a0d0e 100644 --- a/test/sequential/test-util-debug.js +++ b/test/sequential/test-util-debug.js @@ -26,6 +26,11 @@ function test(environ, shouldWrite) { var spawn = require('child_process').spawn; var child = spawn(process.execPath, [__filename, 'child'], { + // 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 } }); From 28c2e2ef262c1defc99e023a1c41d0a88ef5000d Mon Sep 17 00:00:00 2001 From: Glen Keane Date: Fri, 6 Feb 2015 21:45:18 +0000 Subject: [PATCH 3/5] fix nits for review --- src/node_lttng.cc | 8 ++++---- src/node_lttng.h | 2 +- src/node_lttng_provider.h | 2 +- src/node_lttng_tp.h | 3 +-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/node_lttng.cc b/src/node_lttng.cc index 7369dd47441cb7..78cab16cc180ca 100644 --- a/src/node_lttng.cc +++ b/src/node_lttng.cc @@ -141,7 +141,7 @@ void LTTNG_HTTP_SERVER_REQUEST(const FunctionCallbackInfo& args) { return; Environment* env = Environment::GetCurrent(args); - Local arg0 = Local::Cast(args[0]); + Local arg0 = args[0].As(); Local headers; memset(&req, 0, sizeof(req)); @@ -157,10 +157,10 @@ void LTTNG_HTTP_SERVER_REQUEST(const FunctionCallbackInfo& args) { Local strfwdfor = headers->Get(env->x_forwarded_string()); node::Utf8Value fwdfor(env->isolate(), strfwdfor); - req.forwardedFor = *fwdfor; + req.forwarded_for = *fwdfor; - if (!strfwdfor->IsString() || req.forwardedFor == nullptr) - req.forwardedFor = const_cast(""); + if (!strfwdfor->IsString() || req.forwarded_for == nullptr) + req.forwarded_for = const_cast(""); SLURP_CONNECTION(args[1], conn); NODE_HTTP_SERVER_REQUEST(&req, &conn, conn.remote, conn.port, req.method, \ diff --git a/src/node_lttng.h b/src/node_lttng.h index 76bf799a1fefb8..cae35e141a389a 100644 --- a/src/node_lttng.h +++ b/src/node_lttng.h @@ -25,7 +25,7 @@ typedef struct { } _un; char* url; char* method; - char* forwardedFor; + const char* forwarded_for; char* _pad[8]; } node_lttng_http_server_request_t; diff --git a/src/node_lttng_provider.h b/src/node_lttng_provider.h index 88c1f7126ce47d..22dd935a95f464 100644 --- a/src/node_lttng_provider.h +++ b/src/node_lttng_provider.h @@ -13,7 +13,7 @@ void NODE_HTTP_SERVER_REQUEST(node_lttng_http_server_request_t* req, const char *method, const char *url, int fd) { tracepoint(node, http_server_request, req->url, req->method, \ - req->forwardedFor); + req->forwarded_for); } void NODE_HTTP_SERVER_RESPONSE(node_lttng_connection_t* conn, diff --git a/src/node_lttng_tp.h b/src/node_lttng_tp.h index 6925ed3e0ad8ff..b45d630d8d61ec 100644 --- a/src/node_lttng_tp.h +++ b/src/node_lttng_tp.h @@ -15,7 +15,7 @@ TRACEPOINT_EVENT( TP_ARGS( char*, url, char*, method, - char*, forwardedFor + const char*, forwardedFor ), TP_FIELDS( ctf_string(url, url) @@ -52,7 +52,6 @@ TRACEPOINT_EVENT( ) ) -// DBTODO - sort out BYTE_ORDER issue with ints TRACEPOINT_EVENT( node, http_client_response, From b8a72b5358262e8b49d2cc8f5ebfa3141bf84087 Mon Sep 17 00:00:00 2001 From: Glen Keane Date: Fri, 6 Feb 2015 22:31:36 +0000 Subject: [PATCH 4/5] fix missing cast nit --- src/node_lttng.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_lttng.cc b/src/node_lttng.cc index 78cab16cc180ca..c5d5d09dfcb4c2 100644 --- a/src/node_lttng.cc +++ b/src/node_lttng.cc @@ -192,7 +192,7 @@ void LTTNG_HTTP_CLIENT_REQUEST(const FunctionCallbackInfo& args) { * caller here to retain their method and URL until the time at which * LTTNG_HTTP_CLIENT_REQUEST can be called. */ - Local arg0 = Local::Cast(args[0]); + Local arg0 = args[0].As(); SLURP_STRING(arg0, _header, &header); req.method = header; From fde51f1ff5ab1e60ae438c402176fe34cbae59ac Mon Sep 17 00:00:00 2001 From: Glen Keane Date: Sat, 7 Feb 2015 19:32:17 +0000 Subject: [PATCH 5/5] fix missing cast nit --- src/node_lttng.cc | 2 +- src/node_lttng.h | 12 ++++++------ src/node_lttng_tp.h | 16 ++++++++-------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/node_lttng.cc b/src/node_lttng.cc index c5d5d09dfcb4c2..5ec884385c8ed4 100644 --- a/src/node_lttng.cc +++ b/src/node_lttng.cc @@ -160,7 +160,7 @@ void LTTNG_HTTP_SERVER_REQUEST(const FunctionCallbackInfo& args) { req.forwarded_for = *fwdfor; if (!strfwdfor->IsString() || req.forwarded_for == nullptr) - req.forwarded_for = const_cast(""); + req.forwarded_for = ""; SLURP_CONNECTION(args[1], conn); NODE_HTTP_SERVER_REQUEST(&req, &conn, conn.remote, conn.port, req.method, \ diff --git a/src/node_lttng.h b/src/node_lttng.h index cae35e141a389a..31f706f7582402 100644 --- a/src/node_lttng.h +++ b/src/node_lttng.h @@ -9,13 +9,13 @@ extern "C" { typedef struct { int32_t fd; int32_t port; - char* remote; + const char* remote; int32_t buffered; } node_lttng_connection_t; typedef struct { - char* url; - char* method; + const char* url; + const char* method; } node_lttng_http_client_request_t; typedef struct { @@ -23,10 +23,10 @@ typedef struct { uint32_t version; uintptr_t unused; /* for compat. with old 64-bit struct */ } _un; - char* url; - char* method; + const char* url; + const char* method; const char* forwarded_for; - char* _pad[8]; + const char* _pad[8]; } node_lttng_http_server_request_t; } // extern "C" diff --git a/src/node_lttng_tp.h b/src/node_lttng_tp.h index b45d630d8d61ec..53d04f47a80e5a 100644 --- a/src/node_lttng_tp.h +++ b/src/node_lttng_tp.h @@ -13,8 +13,8 @@ TRACEPOINT_EVENT( node, http_server_request, TP_ARGS( - char*, url, - char*, method, + const char*, url, + const char*, method, const char*, forwardedFor ), TP_FIELDS( @@ -29,7 +29,7 @@ TRACEPOINT_EVENT( http_server_response, TP_ARGS( int, port, - char*, remote, + const char*, remote, int, fd ), TP_FIELDS( @@ -43,8 +43,8 @@ TRACEPOINT_EVENT( node, http_client_request, TP_ARGS( - char*, url, - char*, method + const char*, url, + const char*, method ), TP_FIELDS( ctf_string(url, url) @@ -57,7 +57,7 @@ TRACEPOINT_EVENT( http_client_response, TP_ARGS( int, port, - char*, remote, + const char*, remote, int, fd ), TP_FIELDS( @@ -71,7 +71,7 @@ TRACEPOINT_EVENT( node, net_server_connection, TP_ARGS( - char*, remote, + const char*, remote, int, port, int, fd, int, buffered @@ -88,7 +88,7 @@ TRACEPOINT_EVENT( node, net_stream_end, TP_ARGS( - char*, remote, + const char*, remote, int, port, int, fd ),