1*3f982cf4SFabien Sanglard# Trace Logging Library Usage 2*3f982cf4SFabien Sanglard 3*3f982cf4SFabien SanglardThe idea behind Trace Logging is that we can choose to trace a function and 4*3f982cf4SFabien Sanglardthen, with minimal additional code, determine how long function execution ran 5*3f982cf4SFabien Sanglardfor, whether the function was successful, and connect all of this information to 6*3f982cf4SFabien Sanglardany existing informational logs. The below provides information about how this 7*3f982cf4SFabien Sanglardcan be achieved with OSP's TraceLogging Infrastructure. 8*3f982cf4SFabien Sanglard 9*3f982cf4SFabien Sanglard## Compilation 10*3f982cf4SFabien Sanglard 11*3f982cf4SFabien SanglardBy default, TraceLogging is enabled as part of the build. 12*3f982cf4SFabien SanglardTo disable TraceLogging, include flag `--args="enable_trace_logging=false"` 13*3f982cf4SFabien Sanglardwhen calling `gn gen` as part of building this library. 14*3f982cf4SFabien Sanglard 15*3f982cf4SFabien Sanglard## Imports 16*3f982cf4SFabien Sanglard 17*3f982cf4SFabien SanglardTo use TraceLogging, import the following header file: 18*3f982cf4SFabien Sanglard * *util/trace_logging.h* 19*3f982cf4SFabien SanglardThis file will import all other Trace Logging dependencies. 20*3f982cf4SFabien Sanglard 21*3f982cf4SFabien Sanglard## Trace IDs 22*3f982cf4SFabien Sanglard 23*3f982cf4SFabien SanglardWhen a Trace Log is created, a new unsigned integer is associated with this 24*3f982cf4SFabien Sanglardspecific trace, which will going forward be referred to as a Trace ID. 25*3f982cf4SFabien SanglardAssociating a Trace ID has the following benefits: 26*3f982cf4SFabien Sanglard 27*3f982cf4SFabien Sanglard* The same Trace ID can be associated with all Informational Logs generated 28*3f982cf4SFabien Sanglard during this traced method’s execution. This will allow for all informational 29*3f982cf4SFabien Sanglard logs to easily be associated with a method execution, so that if an unexpected 30*3f982cf4SFabien Sanglard failure occurs or edge case pops up we will have additional information useful 31*3f982cf4SFabien Sanglard in debugging this issue and can more easily determine the state of the system 32*3f982cf4SFabien Sanglard leading to this issue. 33*3f982cf4SFabien Sanglard 34*3f982cf4SFabien Sanglard* If another Trace Log is created during the execution of this first traced 35*3f982cf4SFabien Sanglard method, we will have a hierarchy of Trace IDs. This will allow us to easily 36*3f982cf4SFabien Sanglard create an execution tree (through trivial scripting, preexisting tool, or 37*3f982cf4SFabien Sanglard database operations) to get a better view of how execution is proceeding. 38*3f982cf4SFabien Sanglard Together, the IDs associated with these calls form a Trace ID Hierarchy. The 39*3f982cf4SFabien Sanglard Hierarchy has the following format: 40*3f982cf4SFabien Sanglard * *Current Trace ID*: The ID of the function currently being traced. 41*3f982cf4SFabien Sanglard * *Parent Trace ID*: The ID of the function which was being traced when this 42*3f982cf4SFabien Sanglard Trace was initiated. 43*3f982cf4SFabien Sanglard * *Root Trace ID*: The ID of the first traced function under which this the 44*3f982cf4SFabien Sanglard current Trace was called. 45*3f982cf4SFabien Sanglard 46*3f982cf4SFabien SanglardAs an example: 47*3f982cf4SFabien Sanglard``` cpp 48*3f982cf4SFabien Sanglard public void DoThings() { 49*3f982cf4SFabien Sanglard TRACE_SCOPED(category, "outside"); 50*3f982cf4SFabien Sanglard { 51*3f982cf4SFabien Sanglard TRACE_SCOPED(category, "middle"); 52*3f982cf4SFabien Sanglard { 53*3f982cf4SFabien Sanglard TRACE_SCOPED(category, "inside"); 54*3f982cf4SFabien Sanglard } 55*3f982cf4SFabien Sanglard } 56*3f982cf4SFabien Sanglard } 57*3f982cf4SFabien Sanglard``` 58*3f982cf4SFabien Sanglard 59*3f982cf4SFabien SanglardThis could result in the following Trace ID Information: 60*3f982cf4SFabien Sanglard 61*3f982cf4SFabien Sanglard| NAME | ROOT ID | PARENT ID | TRACE ID | RESULT | 62*3f982cf4SFabien Sanglard|---------|----------|------------|-----------|---------| 63*3f982cf4SFabien Sanglard| outside | 100 | 0 | 100 | success | 64*3f982cf4SFabien Sanglard| middle | 100 | 100 | 101 | success | 65*3f982cf4SFabien Sanglard| inside | 100 | 101 | 102 | success | 66*3f982cf4SFabien Sanglard 67*3f982cf4SFabien SanglardNote that, prior to any trace calls, the Trace ID is considered to be 0x0 by 68*3f982cf4SFabien Sanglardconvention. 69*3f982cf4SFabien Sanglard 70*3f982cf4SFabien Sanglard## Trace Results 71*3f982cf4SFabien Sanglard 72*3f982cf4SFabien SanglardThe "result" of a trace is meant to indicate whether the traced function 73*3f982cf4SFabien Sanglardcompleted successfully or not. Results are handled differently for synchronous 74*3f982cf4SFabien Sanglardand asynchronous traces. 75*3f982cf4SFabien Sanglard 76*3f982cf4SFabien SanglardFor scoped traces, the trace is by default assumed to be successful. If an error 77*3f982cf4SFabien Sanglardstate is desired, this should be set using `TRACE_SET_RESULT(result)` where 78*3f982cf4SFabien Sanglardresult is some Error::Code enum value. 79*3f982cf4SFabien Sanglard 80*3f982cf4SFabien SanglardFor asynchronous calls, the result must be set as part of the `TRACE_ASYNC_END` 81*3f982cf4SFabien Sanglardcall. As with scoped traces, the result must be some Error::Code enum value. 82*3f982cf4SFabien Sanglard 83*3f982cf4SFabien Sanglard## Tracing Functions 84*3f982cf4SFabien SanglardAll of the below functions rely on the Platform Layer's IsTraceLoggingEnabled() 85*3f982cf4SFabien Sanglardfunction. When logging is disabled, either for the specific category of trace 86*3f982cf4SFabien Sanglardlogging which the Macro specifies or for TraceCategory::Any in all other cases, 87*3f982cf4SFabien Sanglardthe below functions will be treated as a NoOp. 88*3f982cf4SFabien Sanglard 89*3f982cf4SFabien Sanglard### Synchronous Tracing 90*3f982cf4SFabien Sanglard ```c++ 91*3f982cf4SFabien Sanglard TRACE_SCOPED(category, name) 92*3f982cf4SFabien Sanglard TRACE_SCOPED(category, name, traceId, parentId, rootId) 93*3f982cf4SFabien Sanglard TRACE_SCOPED(category, name, traceIdHierarchy) 94*3f982cf4SFabien Sanglard ``` 95*3f982cf4SFabien Sanglard If logging is enabled for the provided |category|, trace the current scope. The scope 96*3f982cf4SFabien Sanglard should encompass the operation described by |name|. The latter two uses of this macro are 97*3f982cf4SFabien Sanglard for manually providing the trace ID hierarchy; the first auto-generates a new trace ID for 98*3f982cf4SFabien Sanglard this scope and sets its parent trace ID to that of the encompassing scope (if any). 99*3f982cf4SFabien Sanglard 100*3f982cf4SFabien Sanglard ```c++ 101*3f982cf4SFabien Sanglard TRACE_DEFAULT_SCOPED(category) 102*3f982cf4SFabien Sanglard TRACE_DEFAULT_SCOPED(category, traceId, parentId, rootId) 103*3f982cf4SFabien Sanglard TRACE_DEFAULT_SCOPED(category, traceIdHierarchy) 104*3f982cf4SFabien Sanglard ``` 105*3f982cf4SFabien Sanglard Same as TRACE_SCOPED(), but use the current function/method signature as the operation 106*3f982cf4SFabien Sanglard name. 107*3f982cf4SFabien Sanglard 108*3f982cf4SFabien Sanglard### Asynchronous Tracing 109*3f982cf4SFabien Sanglard `TRACE_ASYNC_START(category, name)` 110*3f982cf4SFabien Sanglard If logging is enabled for the provided category, this function will initiate 111*3f982cf4SFabien Sanglard a new asynchronous function trace with name as provided. It will not end 112*3f982cf4SFabien Sanglard until TRACE_ASYNC_END is called with the same Trace ID generated for this 113*3f982cf4SFabien Sanglard async trace. When this call is used, the Trace ID Hierarchy will be 114*3f982cf4SFabien Sanglard determined automatically and the caller does not need to worry about it and, 115*3f982cf4SFabien Sanglard as such, **this call should be used in the majority of asynchronous tracing 116*3f982cf4SFabien Sanglard cases**. 117*3f982cf4SFabien Sanglard 118*3f982cf4SFabien Sanglard `TRACE_ASYNC_START(category, name, traceId, parentId, rootId)` 119*3f982cf4SFabien Sanglard If logging is enabled for the provided category, this function will initiate 120*3f982cf4SFabien Sanglard a new asynchronous function trace with name and full Trac ID Hierarchy as 121*3f982cf4SFabien Sanglard provided. It will not end until TRACE_ASYNC_END is called with the same 122*3f982cf4SFabien Sanglard Trace ID provided for this async trace. Each of trace ID, parent ID, and 123*3f982cf4SFabien Sanglard root ID is optional, so providing only a subset of these values is also 124*3f982cf4SFabien Sanglard valid if the caller only desires to set specific ones. 125*3f982cf4SFabien Sanglard 126*3f982cf4SFabien Sanglard `TRACE_ASYNC_START(category, name, traceIdHierarchy)` 127*3f982cf4SFabien Sanglard This call is intended for use in conjunction with the TRACE_HIERARCHY macro 128*3f982cf4SFabien Sanglard (as described below). this function will initiate a new asynchronous 129*3f982cf4SFabien Sanglard function trace with name and full Trace ID Hierarchy as provided. It will 130*3f982cf4SFabien Sanglard not end until TRACE_ASYNC_END is called with the same Trace ID provided for 131*3f982cf4SFabien Sanglard this async trace. 132*3f982cf4SFabien Sanglard 133*3f982cf4SFabien Sanglard `TRACE_ASYNC_END(category, id, result)` 134*3f982cf4SFabien Sanglard This call will end a trace initiated by TRACE_ASYNC_START (as described 135*3f982cf4SFabien Sanglard above) if logging is enabled for the associated category. The id is expected 136*3f982cf4SFabien Sanglard to match that used by an TRACE_ASYNC_START call, and result is the same as 137*3f982cf4SFabien Sanglard TRACE_SET_RESULT's argument. 138*3f982cf4SFabien Sanglard 139*3f982cf4SFabien Sanglard### Other Tracing Macros 140*3f982cf4SFabien Sanglard `TRACE_CURRENT_ID` 141*3f982cf4SFabien Sanglard This macro returns the current Trace ID at this point in time. 142*3f982cf4SFabien Sanglard 143*3f982cf4SFabien Sanglard `TRACE_ROOT_ID` 144*3f982cf4SFabien Sanglard This macro returns the root Trace ID at this point in time. 145*3f982cf4SFabien Sanglard 146*3f982cf4SFabien Sanglard `TRACE_HIERARCHY` 147*3f982cf4SFabien Sanglard This macro returns an instance of struct Trace ID Hierarchy containing the 148*3f982cf4SFabien Sanglard current Trace ID Hierarchy. This is intended to be used with 149*3f982cf4SFabien Sanglard `TRACE_SET_HIERARCHY` (described below) so that Trace ID Hierarchy can be 150*3f982cf4SFabien Sanglard maintained when crossing thread or machine boundaries. 151*3f982cf4SFabien Sanglard 152*3f982cf4SFabien Sanglard `TRACE_SET_HIERARCHY(ids)` 153*3f982cf4SFabien Sanglard This macro sets the current Trace Id Hierarchy without initiating a scoped 154*3f982cf4SFabien Sanglard trace. The set ids will cease to apply when the current scope ends. This is 155*3f982cf4SFabien Sanglard intended to be used with `TRACE_HIERARCHY` (described above) so that Trace 156*3f982cf4SFabien Sanglard ID Hierarchy can be maintained when crossing thread or machine boundaries. 157*3f982cf4SFabien Sanglard 158*3f982cf4SFabien Sanglard `TRACE_SET_RESULT(result)` 159*3f982cf4SFabien Sanglard Sets the current scoped trace's result to be the same as the Error::Code 160*3f982cf4SFabien Sanglard argument provided. 161*3f982cf4SFabien Sanglard 162*3f982cf4SFabien Sanglard### Example Code 163*3f982cf4SFabien SanglardSynchronous Tracing: 164*3f982cf4SFabien Sanglard``` cpp 165*3f982cf4SFabien Sanglard public void DoThings() { 166*3f982cf4SFabien Sanglard TRACE_SCOPED(category, "DoThings"); 167*3f982cf4SFabien Sanglard 168*3f982cf4SFabien Sanglard // Do Things. 169*3f982cf4SFabien Sanglard // A trace log is generated when the scope containing the above call ends. 170*3f982cf4SFabien Sanglard 171*3f982cf4SFabien Sanglard TRACE_SET_RESULT(Error::Code::kNone); 172*3f982cf4SFabien Sanglard } 173*3f982cf4SFabien Sanglard``` 174*3f982cf4SFabien Sanglard 175*3f982cf4SFabien SanglardAsynchronous tracing with known Trace ID (recommended): 176*3f982cf4SFabien SanglardThis approach allows for asynchronous tracing when the function being traced can 177*3f982cf4SFabien Sanglardbe associated with a known Trace ID. For instance, a packet ID, a request ID, or 178*3f982cf4SFabien Sanglardanother ID which will live for the duration of the trace but will not need to be 179*3f982cf4SFabien Sanglardpassed around separately. 180*3f982cf4SFabien Sanglard``` cpp 181*3f982cf4SFabien Sanglard public void DoThingsStart() { 182*3f982cf4SFabien Sanglard TRACE_ASYNC_START(category, "DoThings", kKnownId); 183*3f982cf4SFabien Sanglard } 184*3f982cf4SFabien Sanglard 185*3f982cf4SFabien Sanglard public void DoThingsEnd() { 186*3f982cf4SFabien Sanglard TRACE_ASYNC_END(category, kKnownId, Error::Code::kNone); 187*3f982cf4SFabien Sanglard } 188*3f982cf4SFabien Sanglard``` 189*3f982cf4SFabien Sanglard 190*3f982cf4SFabien SanglardAsynchronous tracing with unknown Trace ID (not recommended): 191*3f982cf4SFabien SanglardThis approach allows for asynchronous tracing even when no existing ID can be 192*3f982cf4SFabien Sanglardassociated with the trace. 193*3f982cf4SFabien Sanglard``` cpp 194*3f982cf4SFabien Sanglard public TraceId DoThingsStart() { 195*3f982cf4SFabien Sanglard TRACE_ASYNC_START(category, "DoThings"); 196*3f982cf4SFabien Sanglard return TRACE_CURRENT_ID; 197*3f982cf4SFabien Sanglard } 198*3f982cf4SFabien Sanglard 199*3f982cf4SFabien Sanglard public void DoThingsEnd(TraceId trace_id) { 200*3f982cf4SFabien Sanglard TRACE_ASYNC_END(category, trace_id, Error::Code::kNone); 201*3f982cf4SFabien Sanglard } 202*3f982cf4SFabien Sanglard``` 203*3f982cf4SFabien Sanglard 204*3f982cf4SFabien Sanglard## File Division 205*3f982cf4SFabien SanglardThe code for Trace Logging is divided up as follows: 206*3f982cf4SFabien Sanglard * *util/trace_logging.h*: the macros Open Screen library code is expected to 207*3f982cf4SFabien Sanglard use to log trace events. 208*3f982cf4SFabien Sanglard * *platform/base/trace_logging_types.h*: the types/enums used in the platform 209*3f982cf4SFabien Sanglard API as well as internal library code. 210*3f982cf4SFabien Sanglard * *util/trace_logging/*: the internal infrastructure backing the macros in 211*3f982cf4SFabien Sanglard *trace_logging.h*, and connecting it to the platform API. 212*3f982cf4SFabien Sanglard * *platform/api/trace_logging_platform.h*: the platform implementation that is 213*3f982cf4SFabien Sanglard used as the trace logging destination while tracing is active. 214*3f982cf4SFabien SanglardThis information is intended to be only eplanatory for embedders - only the one 215*3f982cf4SFabien Sanglardfile mentioned above in Imports must be imported. 216*3f982cf4SFabien Sanglard 217*3f982cf4SFabien Sanglard## Embedder-Specific Tracing Implementations 218*3f982cf4SFabien Sanglard 219*3f982cf4SFabien SanglardFor an embedder to create a custom TraceLogging implementation: 220*3f982cf4SFabien Sanglard 221*3f982cf4SFabien Sanglard1. *Create a TraceLoggingPlatform* 222*3f982cf4SFabien Sanglard In platform/api/trace_logging_platform.h, the interface TraceLoggingPlatform 223*3f982cf4SFabien Sanglard is defined. An embedder must define a class implementing this interface. The 224*3f982cf4SFabien Sanglard methods should be as performance-optimal as possible, since they might be 225*3f982cf4SFabien Sanglard called frequently (especially `IsLoggingEnabled(TraceCategory)`) and are often 226*3f982cf4SFabien Sanglard in the critical execution path of the library's code. 227*3f982cf4SFabien Sanglard 228*3f982cf4SFabien Sanglard2. *Call `openscreen::StartTracing()` and `StopTracing()`* 229*3f982cf4SFabien Sanglard These activate/deactivate tracing by providing the TraceLoggingPlatform 230*3f982cf4SFabien Sanglard instance and later clearing references to it. 231*3f982cf4SFabien Sanglard 232*3f982cf4SFabien Sanglard**The default implementation of this layer can be seen in 233*3f982cf4SFabien Sanglardplatform/impl/trace_logging_platform.cc.** 234