/////////////////////////////////////////////////////////////////////////////// // pptrace.cpp // // ABSTRACT: // The Event Tracing utility is built on top of the NT Event Tracer base services. // The Event Tracer application programming interface (API) is a set of functions // that developers can use to access and control all aspects of event tracing. Using // the Event Tracer API, developers can manage event tracing sessions, generate event // traces, and receive event traces. The Event Tracer API is divided into sections // based on the functionality implemented: // // Event Trace Controller // Event Trace Provider // Event Trace Consumer // // Event Trace Controller - implemented in pptracelog.exe // Event trace controllers start and stop event tracing sessions, manage buffer resources, // and obtain execution statistics for sessions. Session statistics include the number of // buffers used, the number of buffers delivered, the number of events and buffers lost, // and the size and location of the log file, if applicable. // // Event Trace Provider - APIs used by all ISAPI/COM components are implemented in this file // The event trace provider section of the Event Tracer API is where event trace // providers and classes are registered with the Event Tracer, and event traces and // event trace instances are generated. After registering to generate traces for one // or more classes of events, an event trace provider can be enabled or disabled for // an event tracing session. It is left to the provider to define its interpretation // of being enabled or disabled. In general, if a provider has been enabled, it will // generate event traces for the session to record, and while it is disabled, it will not. // // Event Trace Consumer - implemented in pptracedmp.exe // Software that functions as an event trace consumer can select one or more event // tracing sessions as the source of its event traces. Consumers can receive event // traces stored in log files, or from sessions that deliver event traces in real-time. // When processing event traces, a consumer can specify starting and ending times, and // only events that occur in the specified time frame will be delivered to the consumer. // A consumer can request events from multiple event tracing sessions simultaneously, // and the Event Tracer will put the events into chronological order before delivering // them to the consumer. // HISTORY: // 05-15-01 - naiyij created // /////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #define MAXIMUM_LOGGERS 32 #define IsEqualGUID(rguid1, rguid2) (!memcmp(rguid1, rguid2, sizeof(GUID))) GUID TransactionGuid = {0xce5b1020, 0x8ea9, 0x11d0, 0xa4, 0xec, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10}; TRACE_GUID_REGISTRATION TraceGuidReg[] = { { (LPGUID)&TransactionGuid, NULL } }; typedef struct _USER_MOF_EVENT { EVENT_TRACE_HEADER Header; MOF_FIELD mofData; } USER_MOF_EVENT, *PUSER_MOF_EVENT; TRACEHANDLE LoggerHandle; TRACEHANDLE RegistrationHandle; namespace PPTraceStatus { bool TraceOnFlag = false; UCHAR EnableLevel = 0; ULONG EnableFlags = 0; } // TRACEHANDLE is typedefed as ULONG64 ULONG64 GetTraceHandle() { return LoggerHandle; } // TRACEHANDLE is typedefed as ULONG64 void SetTraceHandle(ULONG64 TraceHandle) { LoggerHandle = TraceHandle; } /////////////////////////////////////////////////////////////////////////// // TraceString // Genereate a Trace Event with the input string // unicode version - for future use /////////////////////////////////////////////////////////////////////////// ULONG TraceString(UCHAR Level, IN LPCWSTR wszBuf) { ULONG status; PMOF_FIELD mofField; USER_MOF_EVENT UserMofEvent; RtlZeroMemory(&UserMofEvent, sizeof(UserMofEvent)); UserMofEvent.Header.Class.Type = EVENT_TRACE_TYPE_INFO; UserMofEvent.Header.Class.Level = Level; UserMofEvent.Header.Size = sizeof(UserMofEvent); UserMofEvent.Header.Flags = WNODE_FLAG_TRACED_GUID; UserMofEvent.Header.Guid = TransactionGuid; UserMofEvent.Header.Flags |= WNODE_FLAG_USE_MOF_PTR; mofField = (PMOF_FIELD) & UserMofEvent.mofData; mofField->DataPtr = (ULONGLONG) (wszBuf); mofField->Length = sizeof(WCHAR) * (wcslen(wszBuf) + 1); status = TraceEvent(LoggerHandle, (PEVENT_TRACE_HEADER) & UserMofEvent); return status; } /////////////////////////////////////////////////////////////////////////// // TraceString // Genereate a Trace Event with the input string // ansi version - used currently /////////////////////////////////////////////////////////////////////////// ULONG TraceString(UCHAR Level, IN LPCSTR szBuf) { ULONG status; PMOF_FIELD mofField; USER_MOF_EVENT UserMofEvent; RtlZeroMemory(&UserMofEvent, sizeof(UserMofEvent)); UserMofEvent.Header.Class.Type = EVENT_TRACE_TYPE_INFO; UserMofEvent.Header.Class.Level = Level; UserMofEvent.Header.Size = sizeof(UserMofEvent); UserMofEvent.Header.Flags = WNODE_FLAG_TRACED_GUID; UserMofEvent.Header.Guid = TransactionGuid; UserMofEvent.Header.Flags |= WNODE_FLAG_USE_MOF_PTR; mofField = (PMOF_FIELD) & UserMofEvent.mofData; mofField->DataPtr = (ULONGLONG) (szBuf); mofField->Length = sizeof(CHAR) * (strlen(szBuf) + 1); status = TraceEvent(LoggerHandle, (PEVENT_TRACE_HEADER) & UserMofEvent); return status; } //--------------------------------------------------------------------------------------- // // @func Calls TracePrint to print a string that is potentially longer than MAXSTR // // @rdesc does not return any value // //--------------------------------------------------------------------------------------- VOID TracePrintString( UCHAR Level, //@parm log if current logging level is at least this LPCSTR szFileAndLine, //@parm ignored LPCSTR szContext, //@parm which function is this called from LPCSTR szBuf //@parm the string itself ) { ATLASSERT(szContext); TraceString(Level, szContext); TraceString(Level, szBuf); } /////////////////////////////////////////////////////////////////////////// // TracePrintBlob // Generate a trace event with input binary blob /////////////////////////////////////////////////////////////////////////// #define TOHEX(h) ((h)>=10 ? 'a' +(h)-10 : '0'+(h)) VOID TracePrintBlob( UCHAR Level, LPCSTR szFileAndLine, LPCSTR szDesc, LPBYTE binBlob, DWORD cSize, BOOL bUnderscore) //defaults to FALSE { // no data generated for the following two cases if (!PPTraceStatus::TraceOnFlag || Level > PPTraceStatus::EnableLevel) return; _ASSERT(szFileAndLine && szDesc); _ASSERT(*szFileAndLine && *szDesc); _ASSERT(binBlob && !IsBadReadPtr(binBlob, cSize)); char* pBuf = NULL; char* pAscii = NULL; // the buffer to hold the hex version of the blob and other stuff + NULL + @ pBuf = new char [strlen(szFileAndLine) + cSize * 2 + 2]; pAscii = new char [cSize * (bUnderscore ? 2 : 1)+ 1]; if (!pBuf || !pAscii) { TraceString(Level, "not enough memory for this trace"); } else { char* pNext = pBuf; char* pNextAscii = pAscii; BYTE cValue; BYTE cHalf; // convert the blob to hex chars for (DWORD i = 0; i < cSize; ++i) { cValue = *binBlob++; cHalf = cValue >> 4; *pNext++ = TOHEX(cHalf); cHalf = cValue & 0x0f; *pNext++ = TOHEX(cHalf); if (isprint(cValue)) { *pNextAscii++ = cValue; if (bUnderscore) *pNextAscii++ = '_'; } else { *pNextAscii++ = '?'; if (bUnderscore) *pNextAscii++ = '?'; } } *pNext++ = '@'; CHAR* pStr = strrchr(szFileAndLine, '\\'); if(pStr) { strcpy(pNext, ++pStr); pNext += strlen(pStr); } *pNext = '\0'; *pNextAscii = '\0'; TraceString(Level, szDesc); TraceString(Level, pAscii); TraceString(Level, pBuf); } if (pBuf) delete [] pBuf; if (pAscii) delete [] pAscii; } /////////////////////////////////////////////////////////////////////////// // TracePrint // Generate a trace event with input data /////////////////////////////////////////////////////////////////////////// VOID TracePrint( UCHAR Level, LPCSTR szFileAndLine, LPCSTR ParameterList OPTIONAL, ... ) { // no data generated for the following two cases if (!PPTraceStatus::TraceOnFlag || Level > PPTraceStatus::EnableLevel) return; CHAR buf[MAXSTR]; int len = 0; if (ARGUMENT_PRESENT(ParameterList)) { va_list parms; va_start(parms, ParameterList); len = _vsnprintf(buf, MAXSTR-1, (CHAR*)ParameterList, parms); if (len < 0) len = MAXSTR - 1; va_end(parms); } if (len < (MAXSTR - 1)) { CHAR* pStr = strrchr(szFileAndLine, '\\'); if (pStr) { pStr++; _snprintf(buf+len, MAXSTR-len-1, "@%s", pStr); } } TraceString(Level, buf); } /////////////////////////////////////////////////////////////////////////// // CTraceFuncVoid // Generate trace events for void functions /////////////////////////////////////////////////////////////////////////// CTraceFuncVoid::CTraceFuncVoid(UCHAR Level, LPCSTR szFileAndLine, LPCSTR szFuncName, LPCSTR ParameterList, ...) : m_Level(Level) { // no data generated for the following two cases if (!PPTraceStatus::TraceOnFlag || m_Level > PPTraceStatus::EnableLevel) return; strncpy(m_szFuncName, szFuncName, MAXNAME-1); CHAR buf[MAXSTR]; int len = _snprintf(buf, MAXSTR-1, "+%s(", m_szFuncName); int count = 0; if (ARGUMENT_PRESENT(ParameterList)) { va_list parms; va_start(parms, ParameterList); count = _vsnprintf(buf+len, MAXSTR-len-1, (CHAR*)ParameterList, parms); len = (count > 0) ? len + count : MAXSTR - 1; va_end(parms); } if (len < (MAXSTR - 1)) { CHAR* pStr = strrchr(szFileAndLine, '\\'); if (pStr) { pStr++; //remove '\' _snprintf(buf+len, MAXSTR-len-1, ")@%s", pStr); } } TraceString(m_Level, buf); }; CTraceFuncVoid::~CTraceFuncVoid() { // no data generated for the following two cases if (!PPTraceStatus::TraceOnFlag || m_Level > PPTraceStatus::EnableLevel) return; std::ostringstream ost; ost << "-" << m_szFuncName << "()"; TraceString(m_Level, ost.str().c_str()); };