-
Notifications
You must be signed in to change notification settings - Fork 6
/
trace_log.h
382 lines (341 loc) · 12.2 KB
/
trace_log.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
* Copyright 2016-Present Couchbase, Inc.
*
* Use of this software is governed by the Business Source License included
* in the file licenses/BSL-Couchbase.txt. As of the Change Date specified
* in that file, in accordance with the Business Source License, use of this
* software will be governed by the Apache License, Version 2.0, included in
* the file licenses/APL2.txt.
*/
#pragma once
#include <atomic>
#include <memory>
#include <mutex>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include "category_registry.h"
#include "chunk_lock.h"
#include "trace_buffer.h"
#include "trace_config.h"
#include "trace_context.h"
#include "trace_event.h"
namespace phosphor {
/**
* The TraceLog class is the main public management interface
* of Phosphor. Generally the TraceLog is used as a singleton,
* this instance is acquired via TraceLog::getInstance().
*
* Logging can be enabled by passing in a TraceConfig object with
* the desired options to the TraceConfig::start() method:
*
* // Enable tracing with a fixed buffer, 5 megabytes in size
* TraceLog::getInstance().start(TraceConfig(BufferMode::fixed,
* 5 * 1024 * 1024))
*
* Once enabled, tracing will be logged wherever code has been
* instrumented with the instrumentation API described in phosphor.h.
*
* This class's public interface is *generally* thread-safe.
*/
class TraceLog {
public:
/**
* Constructor for creating a TraceLog with a specific log
* config
*
* @param _config The TraceLogConfig to be used by the TraceLog
*/
TraceLog(const TraceLogConfig& _config);
/**
* Constructor for generating a TraceLog from the current
* environment according to the rules set out in TraceLogConfig.
*
* Will additionally start tracing if the `PHOSPHOR_TRACING_START`
* environment variable is appropriately configured according to
* the rules for TraceConfig::fromString
*
* @return The configured TraceLog
*/
TraceLog();
~TraceLog();
/**
* Used to perform a one-time configuration of the TraceLog
*
* @param _config The TraceLogConfig to be used by the TraceLog
*/
void configure(const TraceLogConfig& _config);
/**
* Singleton static method to get the TraceLog instance
*
* This is technically ThreadSafe according to the C++11 spec
* but versions of MSVC < 2015 are not *quite* conforming.
*
* @return the TraceLog instance
*/
static TraceLog& getInstance();
/**
* Start tracing with the specified config
*
* @param _trace_config TraceConfig to use for this tracing run
*/
void start(const TraceConfig& _trace_config);
/**
* Start tracing with the specified config and using an external lock
*
* @param lock guard holding the external lock
* @param _trace_config TraceConfig to use for this tracing run
*/
void start(std::lock_guard<TraceLog>&, const TraceConfig& _trace_config);
/**
* Immediately stops tracing
*/
void stop(bool shutdown = false);
/**
* Immediately stops tracing (With external locking)
*
* @param Lock guard holding the external lock
*/
void stop(std::lock_guard<TraceLog>&, bool shutdown = false);
/**
* Logs an event in the current buffer (if applicable)
*
* This method should not be used directly, instead the
* macros contained within phosphor.h should be used instead.
*
* @param tpi Tracepoint info (name, category, etc) of the event.
* @param argA Argument to be saved with the event
* @param argB Argument to be saved with the event
*/
void logEvent(const tracepoint_info* tpi,
TraceArgument argA,
TraceArgument argB);
/**
* Logs a Complete event in the current buffer (if applicable)
*
* This method should not be used directly, instead the
* macros contained within phosphor.h should be used instead.
*
* @param tpi Tracepoint information (name, category, ...)
* @param start Start time of the event
* @param duration Duration of the event
* @param argA Argument to be saved with the event
* @param argB Argument to be saved with the event
*/
void logEvent(const tracepoint_info* tpi,
std::chrono::steady_clock::time_point start,
std::chrono::steady_clock::duration duration,
TraceArgument argA,
TraceArgument argB);
/**
* Used to get a reference to a reusable CategoryStatus. This should
* generally be held in a block-scope static at a given trace point
* to verify if the category for that trace point is presently
* enabled.
*
* @param category_group The category group to check
* @return const reference to the CategoryStatus atomic that holds
* that status for the given category group
*/
const AtomicCategoryStatus& getCategoryStatus(const char* category_group);
/**
* Transfers ownership of the current TraceBuffer to the caller
*
* Should only be called while Tracing is disabled. The returned
* unique_ptr is not guaranteed to be non-null, and in fact *will*
* be null if the buffer has previously been retrieved.
*
* @return TraceBuffer
* @throw std::logic_error if tracing is currently enabled
*/
std::unique_ptr<TraceBuffer> getBuffer();
/**
* Same as TraceLog::getBuffer() except with external locking
*
* @param Lock guard holding the external lock
* @return TraceBuffer
* @throw std::logic_error if tracing is currently enabled
*/
std::unique_ptr<TraceBuffer> getBuffer(std::lock_guard<TraceLog>&);
/**
* Returns a trace context object which can be used to generate
* a JSON export / iterated over
*
* @return TraceContext for the last trace
* @throw std::logic_error if tracing is currently enabled
*/
TraceContext getTraceContext();
/**
* Same as TraceLog::getTraceContext() except with external locking
*
* @return TraceContext for the last trace
* @throw std::logic_error if tracing is currently enabled
*/
TraceContext getTraceContext(std::lock_guard<TraceLog>&);
/**
* Get the current state of tracing of this TraceLog
*
* @return True if tracing is enabled, False if tracing is disabled
*/
bool isEnabled() const;
/**
* Registers the current thread for tracing (Optional)
*
* Can also give a name to associate the thread's TID with a name
* for export purposes. Thread name is ignored if it's an empty string.
*
* Registering a thread is used for a long-living thread and is
* used to give it a dedicated ChunkTenant and optionally a
* name. A registered thread MUST be de-registered before the
* thread is joined as the act of registering allocates resources
* only accessibly via thread -local storage.
*
* Registering is desirable as the thread will otherwise share
* a ChunkTenant with all other non-registered threads. Because
* this involves acquiring locks that may be under contention
* this can be expensive.
*
* @param thread_name (optional) name of the thread to register
* @throw std::logic_error if the thread has already been registered
*/
void registerThread(const std::string& thread_name = "");
/**
* De-registers the current thread
*
* De-registering will free up any resources associated with the thread.
* This MUST be called from registered threads before they shutdown to
* prevent memory-leaks as the only reference to resources they allocate
* are in thread local storage.
*/
void deregisterThread();
/**
* Lock the trace log externally
*
* Note: Prefer the internal locking on the methods
*/
void lock() {
mutex.lock();
}
/**
* Unlock the trace log externally
*
* Note: Prefer the internal locking on the methods
*/
void unlock() {
mutex.unlock();
}
TraceConfig getTraceConfig() const;
/**
* Invokes methods on the callback to supply various
* stats about the TraceLog, the active trace buffer
* and the category registry.
*/
void getStats(StatsCallback& addStats) const;
protected:
/**
* Gets a pointer to the appropriate ChunkTenant (or nullptr)
* with the lock acquired.
*
* @return A valid ChunkTenant with available events or a
* nullptr if a valid ChunkTenant could not be acquired.
*/
std::unique_lock<ChunkTenant> getChunkTenant();
/**
* Replaces the current chunk held by the ChunkTenant with a new chunk
* (typically because it is full).
*
* This function must be called while the ChunkTenant lock is held.
*
* @param ct The ChunkTenant that should have it's chunk returned
* and replaced
* @return true if the chunk has been successfully
* replaced, false otherwise
*/
bool replaceChunk(ChunkTenant& ct);
/**
* Used for evicting all ChunkTenants from the log
*
* This will use the set of ChunkTenants established from
* the calls to registerThread and deregisterThread and
* call close() on them.
*
* This will effectively send a message to all ChunkTenants
* that their current references to chunks in their possession
* are no longer valid.
*
* Once this function returns the buffer that the TraceLog had
* SHOULD be safe to be freed / iterated etc.
*/
void evictThreads(std::lock_guard<TraceLog>& lh);
/**
* Removes all threads from the thread_name map that are part of the
* deregistered threads set.
*/
void clearDeregisteredThreads();
/**
* Attempts to stop tracing without waiting for internal lock
*/
void maybe_stop(size_t _generation);
/**
* The current or last-used TraceConfig of the TraceLog, this
* is only ever set by the start() method.
*
* This is a full copy of a TraceConfig rather than a reference
* to allow reuse / modification of a TraceConfig that was
* passed in by a user.
*/
TraceConfig trace_config;
/**
* Whether or not tracing is currently enabled
*
* By transitioning this boolean to false no new trace events
* will be logged, but any threads currently in the process
* of tracing an event MAY finish tracing the event they're on.
*/
std::atomic<bool> enabled;
/**
* mutex is the 'global' lock for the TraceLog and should be
* acquired when modifying the TraceLog itself or the current
* TraceBuffer.
*
* It is not required to be acquired when modifying a loaned out
* TraceChunk contained within a ChunkTenant, this is
* protected by the ChunkTenant's ChunkLock lock instead.
*/
mutable std::mutex mutex;
/**
* buffer is the current buffer that is being used by the TraceLog.
*
* While logging is enabled the buffer will have various chunks of
* the buffer loaned out.
*
* This buffer may become NULL once tracing stops if a user asks for
* it as movement semantics are used and buffers are only created
* when tracing starts.
*/
std::unique_ptr<TraceBuffer> buffer;
/**
* The current tracing generation. This is incremented every-time
* tracing is stopped and is passed into the TraceBuffer when it is
* constructed in order to 'uniquely' identify it.
*/
std::atomic<size_t> generation;
/**
* The set of ChunkTenants that have been registered to this TraceLog.
*/
std::unordered_set<ChunkTenant*> registered_chunk_tenants;
/**
* Category registry which manages the enabled / disabled categories
*/
CategoryRegistry registry;
/**
* Map of registered thread TIDs to names
*/
std::unordered_map<uint64_t, std::string> thread_names;
/**
* List of deregistered thread ids while tracing is running
*/
std::set<uint64_t> deregistered_threads;
};
} // namespace phosphor