diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/node.cc | 12 | ||||
-rw-r--r-- | src/node_dtrace.cc | 9 | ||||
-rw-r--r-- | src/node_win32_etw_provider-inl.h | 141 | ||||
-rw-r--r-- | src/node_win32_etw_provider.cc | 91 | ||||
-rw-r--r-- | src/node_win32_etw_provider.h | 82 | ||||
-rw-r--r-- | src/res/node_etw_provider.man | 102 |
6 files changed, 434 insertions, 3 deletions
diff --git a/src/node.cc b/src/node.cc index 5db4d86c28..d478f06e76 100644 --- a/src/node.cc +++ b/src/node.cc @@ -26,10 +26,14 @@ #include "uv.h" #include "v8-debug.h" -#ifdef HAVE_DTRACE +#if defined HAVE_DTRACE || defined HAVE_ETW # include "node_dtrace.h" #endif +#ifdef HAVE_ETW +# include "node_win32_etw_provider.h" +#endif + #include <locale.h> #include <signal.h> #include <stdio.h> @@ -2325,7 +2329,7 @@ void Load(Handle<Object> process_l) { Local<Object> global = v8::Context::GetCurrent()->Global(); Local<Value> args[1] = { Local<Value>::New(process_l) }; -#ifdef HAVE_DTRACE +#if defined HAVE_DTRACE || defined HAVE_ETW InitDTrace(global); #endif @@ -2894,6 +2898,10 @@ int Start(int argc, char *argv[]) { // watchers, it blocks. uv_run(uv_default_loop()); +#ifdef HAVE_ETW + shutdown_etw(); +#endif + EmitExit(process_l); RunAtExit(); diff --git a/src/node_dtrace.cc b/src/node_dtrace.cc index 01ea7b87fd..e560999c52 100644 --- a/src/node_dtrace.cc +++ b/src/node_dtrace.cc @@ -24,6 +24,9 @@ #ifdef HAVE_DTRACE #include "node_provider.h" +#elif HAVE_ETW +#include "node_win32_etw_provider.h" +#include "node_win32_etw_provider-inl.h" #else #define NODE_HTTP_SERVER_REQUEST(arg0, arg1) #define NODE_HTTP_SERVER_REQUEST_ENABLED() (0) @@ -315,7 +318,11 @@ void InitDTrace(Handle<Object> target) { target->Set(String::NewSymbol(tab[i].name), tab[i].templ->GetFunction()); } -#ifdef HAVE_DTRACE +#ifdef HAVE_ETW + init_etw(); +#endif + +#if defined HAVE_DTRACE || defined HAVE_ETW v8::V8::AddGCPrologueCallback((GCPrologueCallback)dtrace_gc_start); v8::V8::AddGCEpilogueCallback((GCEpilogueCallback)dtrace_gc_done); #endif diff --git a/src/node_win32_etw_provider-inl.h b/src/node_win32_etw_provider-inl.h new file mode 100644 index 0000000000..70b04acba1 --- /dev/null +++ b/src/node_win32_etw_provider-inl.h @@ -0,0 +1,141 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef SRC_ETW_INL_H_ +#define SRC_ETW_INL_H_ + +#include "node_win32_etw_provider.h" +#include "node_etw_provider.h" + +namespace node { + +using namespace v8; + +// From node_win32_etw_provider.cc +extern REGHANDLE node_provider; +extern EventWriteFunc event_write; +extern int events_enabled; + +#define ETW_WRITE_STRING_DATA(data_descriptor, data) \ + EventDataDescCreate(data_descriptor, \ + data, \ + (strlen(data) + 1) * sizeof(char)); + +#define ETW_WRITE_INT32_DATA(data_descriptor, data) \ + EventDataDescCreate(data_descriptor, data, sizeof(int32_t)); + +#define ETW_WRITE_NET_CONNECTION(descriptors, conn) \ + ETW_WRITE_INT32_DATA(descriptors, &conn->fd); \ + ETW_WRITE_INT32_DATA(descriptors + 1, &conn->port); \ + ETW_WRITE_STRING_DATA(descriptors + 2, conn->remote); \ + ETW_WRITE_INT32_DATA(descriptors + 3, &conn->buffered); + +#define ETW_WRITE_HTTP_SERVER_REQUEST(descriptors, req) \ + ETW_WRITE_STRING_DATA(descriptors, req->url); \ + ETW_WRITE_STRING_DATA(descriptors + 1, req->method); \ + ETW_WRITE_STRING_DATA(descriptors + 2, req->forwardedFor); + +#define ETW_WRITE_HTTP_CLIENT_REQUEST(descriptors, req) \ + ETW_WRITE_STRING_DATA(descriptors, req->url); \ + ETW_WRITE_STRING_DATA(descriptors + 1, req->method); + +#define ETW_WRITE_GC(descriptors, type, flags) \ + ETW_WRITE_INT32_DATA(descriptors, &type); \ + ETW_WRITE_INT32_DATA(descriptors + 1, &flags); + +#define ETW_WRITE_EVENT(eventDescriptor, dataDescriptors) \ + DWORD status = event_write(node_provider, \ + &eventDescriptor, \ + sizeof(dataDescriptors)/sizeof(*dataDescriptors),\ + dataDescriptors); \ + assert(status == ERROR_SUCCESS); + + +void NODE_HTTP_SERVER_REQUEST(node_dtrace_http_server_request_t* req, + node_dtrace_connection_t* conn) { + EVENT_DATA_DESCRIPTOR descriptors[7]; + ETW_WRITE_HTTP_SERVER_REQUEST(descriptors, req); + ETW_WRITE_NET_CONNECTION(descriptors + 3, conn); + ETW_WRITE_EVENT(NODE_HTTP_SERVER_REQUEST_EVENT, descriptors); +} + + +void NODE_HTTP_SERVER_RESPONSE(node_dtrace_connection_t* conn) { + EVENT_DATA_DESCRIPTOR descriptors[4]; + ETW_WRITE_NET_CONNECTION(descriptors, conn); + ETW_WRITE_EVENT(NODE_HTTP_SERVER_RESPONSE_EVENT, descriptors); +} + + +void NODE_HTTP_CLIENT_REQUEST(node_dtrace_http_client_request_t* req, + node_dtrace_connection_t* conn) { + EVENT_DATA_DESCRIPTOR descriptors[6]; + ETW_WRITE_HTTP_CLIENT_REQUEST(descriptors, req); + ETW_WRITE_NET_CONNECTION(descriptors + 2, conn); + ETW_WRITE_EVENT(NODE_HTTP_CLIENT_REQUEST_EVENT, descriptors); +} + + +void NODE_HTTP_CLIENT_RESPONSE(node_dtrace_connection_t* conn) { + EVENT_DATA_DESCRIPTOR descriptors[4]; + ETW_WRITE_NET_CONNECTION(descriptors, conn); + ETW_WRITE_EVENT(NODE_HTTP_CLIENT_RESPONSE_EVENT, descriptors); +} + + +void NODE_NET_SERVER_CONNECTION(node_dtrace_connection_t* conn) { + EVENT_DATA_DESCRIPTOR descriptors[4]; + ETW_WRITE_NET_CONNECTION(descriptors, conn); + ETW_WRITE_EVENT(NODE_NET_SERVER_CONNECTION_EVENT, descriptors); +} + + +void NODE_NET_STREAM_END(node_dtrace_connection_t* conn) { + EVENT_DATA_DESCRIPTOR descriptors[4]; + ETW_WRITE_NET_CONNECTION(descriptors, conn); + ETW_WRITE_EVENT(NODE_NET_STREAM_END_EVENT, descriptors); +} + + +void NODE_GC_START(GCType type, GCCallbackFlags flags) { + EVENT_DATA_DESCRIPTOR descriptors[2]; + ETW_WRITE_GC(descriptors, type, flags); + ETW_WRITE_EVENT(NODE_GC_START_EVENT, descriptors); +} + + +void NODE_GC_DONE(GCType type, GCCallbackFlags flags) { + EVENT_DATA_DESCRIPTOR descriptors[2]; + ETW_WRITE_GC(descriptors, type, flags); + ETW_WRITE_EVENT(NODE_GC_DONE_EVENT, descriptors); +} + + +bool NODE_HTTP_SERVER_REQUEST_ENABLED() { return events_enabled > 0; } +bool NODE_HTTP_SERVER_RESPONSE_ENABLED() { return events_enabled > 0; } +bool NODE_HTTP_CLIENT_REQUEST_ENABLED() { return events_enabled > 0; } +bool NODE_HTTP_CLIENT_RESPONSE_ENABLED() { return events_enabled > 0; } +bool NODE_NET_SERVER_CONNECTION_ENABLED() { return events_enabled > 0; } +bool NODE_NET_STREAM_END_ENABLED() { return events_enabled > 0; } +bool NODE_NET_SOCKET_READ_ENABLED() { return events_enabled > 0; } +bool NODE_NET_SOCKET_WRITE_ENABLED() { return events_enabled > 0; } +} +#endif // SRC_ETW_INL_H_
\ No newline at end of file diff --git a/src/node_win32_etw_provider.cc b/src/node_win32_etw_provider.cc new file mode 100644 index 0000000000..78f465c466 --- /dev/null +++ b/src/node_win32_etw_provider.cc @@ -0,0 +1,91 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include "node_dtrace.h" +#include "node_win32_etw_provider.h" +#include "node_etw_provider.h" + +namespace node { + +using namespace v8; + +HMODULE advapi; +REGHANDLE node_provider; +EventRegisterFunc event_register; +EventUnregisterFunc event_unregister; +EventWriteFunc event_write; +int events_enabled; + +// This callback is called by ETW when consumers of our provider +// are enabled or disabled. +// The callback is dispatched on ETW thread. +void NTAPI etw_events_enable_callback( + LPCGUID SourceId, + ULONG IsEnabled, + UCHAR Level, + ULONGLONG MatchAnyKeyword, + ULONGLONG MatchAllKeywords, + PEVENT_FILTER_DESCRIPTOR FilterData, + PVOID CallbackContext) { + if (IsEnabled) { + events_enabled++; + } else { + events_enabled--; + } +} + + +void init_etw() { + events_enabled = 0; + + advapi = LoadLibrary("advapi32.dll"); + if (advapi) { + event_register = (EventRegisterFunc) + GetProcAddress(advapi, "EventRegister"); + event_unregister = (EventUnregisterFunc) + GetProcAddress(advapi, "EventUnregister"); + event_write = (EventWriteFunc)GetProcAddress(advapi, "EventWrite"); + + if (event_register) { + DWORD status = event_register(&NODE_ETW_PROVIDER, + etw_events_enable_callback, + NULL, + &node_provider); + assert(status == ERROR_SUCCESS); + } + } +} + + +void shutdown_etw() { + if (advapi && event_unregister && node_provider) { + event_unregister(node_provider); + node_provider = 0; + } + + events_enabled = 0; + + if (advapi) { + FreeLibrary(advapi); + advapi = NULL; + } +} +}
\ No newline at end of file diff --git a/src/node_win32_etw_provider.h b/src/node_win32_etw_provider.h new file mode 100644 index 0000000000..adfff37e56 --- /dev/null +++ b/src/node_win32_etw_provider.h @@ -0,0 +1,82 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef SRC_ETW_H_ +#define SRC_ETW_H_ + +#include <evntprov.h> +#include "node_dtrace.h" + +namespace node { + +using namespace v8; + +#if defined(_MSC_VER) +# define INLINE __forceinline +#else +# define INLINE inline +#endif + +typedef ULONG (NTAPI *EventRegisterFunc)( + LPCGUID ProviderId, + PENABLECALLBACK EnableCallback, + PVOID CallbackContext, + PREGHANDLE RegHandle +); + +typedef ULONG (NTAPI *EventUnregisterFunc)( + REGHANDLE RegHandle +); + +typedef ULONG (NTAPI *EventWriteFunc)( + REGHANDLE RegHandle, + PCEVENT_DESCRIPTOR EventDescriptor, + ULONG UserDataCount, + PEVENT_DATA_DESCRIPTOR UserData +); + +void init_etw(); +void shutdown_etw(); + +INLINE void NODE_HTTP_SERVER_REQUEST(node_dtrace_http_server_request_t* req, + node_dtrace_connection_t* conn); +INLINE void NODE_HTTP_SERVER_RESPONSE(node_dtrace_connection_t* conn); +INLINE void NODE_HTTP_CLIENT_REQUEST(node_dtrace_http_client_request_t* req, + node_dtrace_connection_t* conn); +INLINE void NODE_HTTP_CLIENT_RESPONSE(node_dtrace_connection_t* conn); +INLINE void NODE_NET_SERVER_CONNECTION(node_dtrace_connection_t* conn); +INLINE void NODE_NET_STREAM_END(node_dtrace_connection_t* conn); +INLINE void NODE_GC_START(GCType type, GCCallbackFlags flags); +INLINE void NODE_GC_DONE(GCType type, GCCallbackFlags flags); + +INLINE bool NODE_HTTP_SERVER_REQUEST_ENABLED(); +INLINE bool NODE_HTTP_SERVER_RESPONSE_ENABLED(); +INLINE bool NODE_HTTP_CLIENT_REQUEST_ENABLED(); +INLINE bool NODE_HTTP_CLIENT_RESPONSE_ENABLED(); +INLINE bool NODE_NET_SERVER_CONNECTION_ENABLED(); +INLINE bool NODE_NET_STREAM_END_ENABLED(); +INLINE bool NODE_NET_SOCKET_READ_ENABLED(); +INLINE bool NODE_NET_SOCKET_WRITE_ENABLED(); + +#define NODE_NET_SOCKET_READ(arg0, arg1) +#define NODE_NET_SOCKET_WRITE(arg0, arg1) +} +#endif // SRC_ETW_H_
\ No newline at end of file diff --git a/src/res/node_etw_provider.man b/src/res/node_etw_provider.man new file mode 100644 index 0000000000..2d96a20c31 --- /dev/null +++ b/src/res/node_etw_provider.man @@ -0,0 +1,102 @@ +<instrumentationManifest + xmlns="http://schemas.microsoft.com/win/2004/08/events" + xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events" + xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <instrumentation> + <events> + <provider name="NodeJS-ETW-provider" + guid="{77754E9B-264B-4D8D-B981-E4135C1ECB0C}" + symbol="NODE_ETW_PROVIDER" + resourceFileName="node.exe" + messageFileName="node.exe"> + + <opcodes> + <opcode name="NODE_HTTP_SERVER_REQUEST" value="10"/> + <opcode name="NODE_HTTP_SERVER_RESPONSE" value="11"/> + <opcode name="NODE_HTTP_CLIENT_REQUEST" value="12"/> + <opcode name="NODE_HTTP_CLIENT_RESPONSE" value="13"/> + <opcode name="NODE_NET_SERVER_CONNECTION" value="14"/> + <opcode name="NODE_NET_STREAM_END" value="15"/> + <opcode name="NODE_GC_START" value="16"/> + <opcode name="NODE_GC_DONE" value="17"/> + </opcodes> + + <templates> + <template tid="node_connection"> + <data name="fd" inType="win:UInt32" /> + <data name="port" inType="win:UInt32" /> + <data name="remote" inType="win:AnsiString" /> + <data name="buffered" inType="win:UInt32" /> + </template> + + <template tid="node_http_client_request"> + <data name="url" inType="win:AnsiString" /> + <data name="method" inType="win:AnsiString" /> + <data name="fd" inType="win:UInt32" /> + <data name="port" inType="win:UInt32" /> + <data name="remote" inType="win:AnsiString" /> + <data name="buffered" inType="win:UInt32" /> + </template> + + <template tid="node_http_server_request"> + <data name="url" inType="win:AnsiString" /> + <data name="method" inType="win:AnsiString" /> + <data name="forwardedFor" inType="win:AnsiString" /> + <data name="fd" inType="win:UInt32" /> + <data name="port" inType="win:UInt32" /> + <data name="remote" inType="win:AnsiString" /> + <data name="buffered" inType="win:UInt32" /> + </template> + + <template tid="node_gc"> + <data name="gctype" inType="win:UInt32" /> + <data name="gccallbackflags" inType="win:UInt32" /> + </template> + </templates> + + <events> + <event value="1" + opcode="NODE_HTTP_SERVER_REQUEST" + template="node_http_server_request" + symbol="NODE_HTTP_SERVER_REQUEST_EVENT" + level="win:Informational"/> + <event value="2" + opcode="NODE_HTTP_SERVER_RESPONSE" + template="node_connection" + symbol="NODE_HTTP_SERVER_RESPONSE_EVENT" + level="win:Informational"/> + <event value="3" + opcode="NODE_HTTP_CLIENT_REQUEST" + template="node_http_client_request" + symbol="NODE_HTTP_CLIENT_REQUEST_EVENT" + level="win:Informational"/> + <event value="4" + opcode="NODE_HTTP_CLIENT_RESPONSE" + template="node_connection" + symbol="NODE_HTTP_CLIENT_RESPONSE_EVENT" + level="win:Informational"/> + <event value="5" + opcode="NODE_NET_SERVER_CONNECTION" + template="node_connection" + symbol="NODE_NET_SERVER_CONNECTION_EVENT" + level="win:Informational"/> + <event value="6" + opcode="NODE_NET_STREAM_END" + template="node_connection" + symbol="NODE_NET_STREAM_END_EVENT" + level="win:Informational"/> + <event value="7" + opcode="NODE_GC_START" + template="node_gc" + symbol="NODE_GC_START_EVENT" + level="win:Informational"/> + <event value="8" + opcode="NODE_GC_DONE" + template="node_gc" + symbol="NODE_GC_DONE_EVENT" + level="win:Informational"/> + </events> + </provider> + </events> + </instrumentation> +</instrumentationManifest> |