2017-05-26 04:48:44 +08:00
|
|
|
/*
|
|
|
|
* Trace.h
|
|
|
|
*
|
|
|
|
* This source file is part of the FoundationDB open source project
|
|
|
|
*
|
|
|
|
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef FLOW_TRACE_H
|
|
|
|
#define FLOW_TRACE_H
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <string>
|
|
|
|
#include <map>
|
2018-10-20 01:30:13 +08:00
|
|
|
#include "flow/IRandom.h"
|
|
|
|
#include "flow/Error.h"
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
#define TRACE_DEFAULT_ROLL_SIZE (10 << 20)
|
|
|
|
#define TRACE_DEFAULT_MAX_LOGS_SIZE (10 * TRACE_DEFAULT_ROLL_SIZE)
|
|
|
|
|
|
|
|
inline int fastrand() {
|
|
|
|
static int g_seed = 0;
|
|
|
|
g_seed = 214013*g_seed + 2531011;
|
|
|
|
return (g_seed>>16)&0x7fff;
|
|
|
|
}
|
|
|
|
|
|
|
|
//inline static bool TRACE_SAMPLE() { return fastrand()<16; }
|
|
|
|
inline static bool TRACE_SAMPLE() { return false; }
|
|
|
|
|
|
|
|
enum Severity {
|
|
|
|
SevSample=1,
|
|
|
|
SevDebug=5,
|
|
|
|
SevInfo=10,
|
|
|
|
SevWarn=20,
|
|
|
|
SevWarnAlways=30,
|
|
|
|
SevError=40,
|
2017-12-16 10:20:33 +08:00
|
|
|
SevMaxUsed=SevError,
|
2017-05-26 04:48:44 +08:00
|
|
|
SevMax=1000000
|
|
|
|
};
|
|
|
|
|
2018-05-03 01:44:38 +08:00
|
|
|
class TraceEventFields {
|
|
|
|
public:
|
|
|
|
typedef std::pair<std::string, std::string> Field;
|
|
|
|
typedef std::vector<Field> FieldContainer;
|
|
|
|
typedef FieldContainer::const_iterator FieldIterator;
|
|
|
|
|
2018-06-01 04:27:35 +08:00
|
|
|
TraceEventFields();
|
|
|
|
|
2018-05-03 01:44:38 +08:00
|
|
|
size_t size() const;
|
2018-06-01 04:27:35 +08:00
|
|
|
size_t sizeBytes() const;
|
2018-05-03 01:44:38 +08:00
|
|
|
FieldIterator begin() const;
|
|
|
|
FieldIterator end() const;
|
|
|
|
|
2018-06-27 05:37:21 +08:00
|
|
|
void addField(const std::string& key, const std::string& value);
|
|
|
|
void addField(std::string&& key, std::string&& value);
|
2018-05-03 01:44:38 +08:00
|
|
|
|
|
|
|
const Field &operator[] (int index) const;
|
|
|
|
bool tryGetValue(std::string key, std::string &outValue) const;
|
|
|
|
std::string getValue(std::string key) const;
|
2019-03-01 01:53:16 +08:00
|
|
|
int getInt(std::string key, bool permissive=false) const;
|
|
|
|
int64_t getInt64(std::string key, bool permissive=false) const;
|
|
|
|
double getDouble(std::string key, bool permissive=false) const;
|
2018-05-03 01:44:38 +08:00
|
|
|
|
|
|
|
std::string toString() const;
|
2018-06-09 04:24:30 +08:00
|
|
|
void validateFormat() const;
|
2018-05-03 01:44:38 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
FieldContainer fields;
|
2018-06-01 04:27:35 +08:00
|
|
|
size_t bytes;
|
2018-05-03 01:44:38 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
template <class Archive>
|
|
|
|
inline void load( Archive& ar, TraceEventFields& value ) {
|
|
|
|
uint32_t count;
|
|
|
|
ar >> count;
|
|
|
|
|
|
|
|
std::string k;
|
|
|
|
std::string v;
|
|
|
|
for(uint32_t i = 0; i < count; ++i) {
|
|
|
|
ar >> k >> v;
|
|
|
|
value.addField(k, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
template <class Archive>
|
|
|
|
inline void save( Archive& ar, const TraceEventFields& value ) {
|
|
|
|
ar << (uint32_t)value.size();
|
|
|
|
|
|
|
|
for(auto itr : value) {
|
|
|
|
ar << itr.first << itr.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
class TraceBatch {
|
|
|
|
public:
|
|
|
|
void addEvent( const char *name, uint64_t id, const char *location );
|
|
|
|
void addAttach( const char *name, uint64_t id, uint64_t to );
|
|
|
|
void addBuggify( int activated, int line, std::string file );
|
|
|
|
void dump();
|
|
|
|
|
|
|
|
private:
|
|
|
|
struct EventInfo {
|
2018-05-03 01:44:38 +08:00
|
|
|
TraceEventFields fields;
|
|
|
|
EventInfo(double time, const char *name, uint64_t id, const char *location);
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct AttachInfo {
|
2018-05-03 01:44:38 +08:00
|
|
|
TraceEventFields fields;
|
|
|
|
AttachInfo(double time, const char *name, uint64_t id, uint64_t to);
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct BuggifyInfo {
|
2018-05-03 01:44:38 +08:00
|
|
|
TraceEventFields fields;
|
|
|
|
BuggifyInfo(double time, int activated, int line, std::string file);
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<EventInfo> eventBatch;
|
|
|
|
std::vector<AttachInfo> attachBatch;
|
|
|
|
std::vector<BuggifyInfo> buggifyBatch;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DynamicEventMetric;
|
|
|
|
class StringRef;
|
|
|
|
template <class T> class Standalone;
|
|
|
|
template <class T> class Optional;
|
|
|
|
|
|
|
|
struct TraceEvent {
|
|
|
|
TraceEvent( const char* type, UID id = UID() ); // Assumes SevInfo severity
|
|
|
|
TraceEvent( Severity, const char* type, UID id = UID() );
|
|
|
|
TraceEvent( struct TraceInterval&, UID id = UID() );
|
|
|
|
TraceEvent( Severity severity, struct TraceInterval& interval, UID id = UID() );
|
|
|
|
|
|
|
|
static void setNetworkThread();
|
|
|
|
static bool isNetworkThread();
|
|
|
|
|
2018-08-02 05:30:57 +08:00
|
|
|
//Must be called directly after constructing the trace event
|
2018-06-27 05:37:21 +08:00
|
|
|
TraceEvent& error(const class Error& e, bool includeCancelled=false);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2018-05-03 01:44:38 +08:00
|
|
|
TraceEvent& detail( std::string key, std::string value );
|
|
|
|
TraceEvent& detail( std::string key, double value );
|
|
|
|
TraceEvent& detail( std::string key, long int value );
|
|
|
|
TraceEvent& detail( std::string key, long unsigned int value );
|
|
|
|
TraceEvent& detail( std::string key, long long int value );
|
|
|
|
TraceEvent& detail( std::string key, long long unsigned int value );
|
|
|
|
TraceEvent& detail( std::string key, int value );
|
|
|
|
TraceEvent& detail( std::string key, unsigned value );
|
2018-06-27 05:37:21 +08:00
|
|
|
TraceEvent& detail( std::string key, const struct NetworkAddress& value );
|
2019-02-28 09:53:38 +08:00
|
|
|
TraceEvent& detail( std::string key, const IPAddress& value );
|
2018-05-03 01:44:38 +08:00
|
|
|
TraceEvent& detailf( std::string key, const char* valueFormat, ... );
|
2018-06-27 05:37:21 +08:00
|
|
|
TraceEvent& detailext( std::string key, const StringRef& value );
|
|
|
|
TraceEvent& detailext( std::string key, const Optional<Standalone<StringRef>>& value );
|
2017-05-26 04:48:44 +08:00
|
|
|
private:
|
2018-05-03 01:44:38 +08:00
|
|
|
// Private version of detailf that does NOT write to the eventMetric. This is to be used by other detail methods
|
2017-05-26 04:48:44 +08:00
|
|
|
// which can write field metrics of a more appropriate type than string but use detailf() to add to the TraceEvent.
|
2018-06-27 05:37:21 +08:00
|
|
|
TraceEvent& detailfNoMetric( std::string&& key, const char* valueFormat, ... );
|
|
|
|
TraceEvent& detailImpl( std::string&& key, std::string&& value, bool writeEventMetricField=true );
|
2017-05-26 04:48:44 +08:00
|
|
|
public:
|
2018-06-27 05:37:21 +08:00
|
|
|
TraceEvent& detail( std::string key, const UID& value );
|
|
|
|
TraceEvent& backtrace(const std::string& prefix = "");
|
2017-05-26 04:48:44 +08:00
|
|
|
TraceEvent& trackLatest( const char* trackingKey );
|
|
|
|
TraceEvent& sample( double sampleRate, bool logSampleRate=true );
|
2018-08-02 05:30:57 +08:00
|
|
|
|
|
|
|
//Cannot call other functions which could disable the trace event afterwords
|
2017-05-26 04:48:44 +08:00
|
|
|
TraceEvent& suppressFor( double duration, bool logSuppressedEventCount=true );
|
|
|
|
|
|
|
|
TraceEvent& GetLastError();
|
|
|
|
|
|
|
|
~TraceEvent(); // Actually logs the event
|
|
|
|
|
2017-12-16 10:20:33 +08:00
|
|
|
// Return the number of invocations of TraceEvent() at the specified logging level.
|
|
|
|
static unsigned long CountEventsLoggedAt(Severity);
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
DynamicEventMetric *tmpEventMetric; // This just just a place to store fields
|
|
|
|
|
|
|
|
private:
|
2018-08-02 05:30:57 +08:00
|
|
|
bool initialized;
|
2017-05-26 04:48:44 +08:00
|
|
|
bool enabled;
|
|
|
|
std::string trackingKey;
|
2018-05-03 01:44:38 +08:00
|
|
|
TraceEventFields fields;
|
2017-05-26 04:48:44 +08:00
|
|
|
Severity severity;
|
|
|
|
const char *type;
|
|
|
|
UID id;
|
2018-08-02 05:30:57 +08:00
|
|
|
Error err;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2017-12-16 10:20:33 +08:00
|
|
|
static unsigned long eventCounts[5];
|
2017-05-26 04:48:44 +08:00
|
|
|
static thread_local bool networkThread;
|
|
|
|
|
2018-08-02 05:30:57 +08:00
|
|
|
bool init();
|
|
|
|
bool init( struct TraceInterval& );
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
2018-06-27 05:37:21 +08:00
|
|
|
struct ITraceLogWriter {
|
2018-06-01 04:27:35 +08:00
|
|
|
virtual void open() = 0;
|
|
|
|
virtual void roll() = 0;
|
|
|
|
virtual void close() = 0;
|
|
|
|
virtual void write(const std::string&) = 0;
|
|
|
|
virtual void sync() = 0;
|
|
|
|
|
|
|
|
virtual void addref() = 0;
|
|
|
|
virtual void delref() = 0;
|
|
|
|
};
|
|
|
|
|
2018-06-27 05:37:21 +08:00
|
|
|
struct ITraceLogFormatter {
|
2018-05-03 01:44:38 +08:00
|
|
|
virtual const char* getExtension() = 0;
|
|
|
|
virtual const char* getHeader() = 0; // Called when starting a new file
|
|
|
|
virtual const char* getFooter() = 0; // Called when ending a file
|
2018-05-12 02:24:20 +08:00
|
|
|
virtual std::string formatEvent(const TraceEventFields&) = 0; // Called for each event
|
2018-05-10 05:35:15 +08:00
|
|
|
|
|
|
|
virtual void addref() = 0;
|
|
|
|
virtual void delref() = 0;
|
2018-05-03 01:44:38 +08:00
|
|
|
};
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
struct TraceInterval {
|
2018-02-17 08:01:19 +08:00
|
|
|
TraceInterval( const char* type ) : count(-1), type(type), severity(SevInfo) {}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
TraceInterval& begin();
|
|
|
|
TraceInterval& end() { return *this; }
|
|
|
|
|
|
|
|
const char* type;
|
|
|
|
UID pairID;
|
|
|
|
int count;
|
2018-02-17 08:01:19 +08:00
|
|
|
Severity severity;
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct LatestEventCache {
|
|
|
|
public:
|
2018-06-27 05:37:21 +08:00
|
|
|
void set( std::string tag, const TraceEventFields& fields );
|
2018-05-03 01:44:38 +08:00
|
|
|
TraceEventFields get( std::string tag );
|
|
|
|
std::vector<TraceEventFields> getAll();
|
|
|
|
std::vector<TraceEventFields> getAllUnsafe();
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
void clear( std::string prefix );
|
|
|
|
void clear();
|
|
|
|
|
|
|
|
// Latest error tracking only tracks errors when called from the main thread. Other errors are silently ignored.
|
2018-06-27 05:37:21 +08:00
|
|
|
void setLatestError( const TraceEventFields& contents );
|
2018-05-03 01:44:38 +08:00
|
|
|
TraceEventFields getLatestError();
|
2017-05-26 04:48:44 +08:00
|
|
|
private:
|
2018-05-03 01:44:38 +08:00
|
|
|
std::map<NetworkAddress, std::map<std::string, TraceEventFields>> latest;
|
|
|
|
std::map<NetworkAddress, TraceEventFields> latestErrors;
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
extern LatestEventCache latestEventCache;
|
|
|
|
|
|
|
|
// Evil but potentially useful for verbose messages:
|
|
|
|
#if CENABLED(0, NOT_IN_CLEAN)
|
|
|
|
#define TRACE( t, m ) if (TraceEvent::isEnabled(t)) TraceEvent(t,m)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct NetworkAddress;
|
|
|
|
void openTraceFile(const NetworkAddress& na, uint64_t rollsize, uint64_t maxLogsSize, std::string directory = ".", std::string baseOfBase = "trace", std::string logGroup = "default");
|
|
|
|
void initTraceEventMetrics();
|
|
|
|
void closeTraceFile();
|
|
|
|
bool traceFileIsOpen();
|
|
|
|
|
2018-12-21 05:51:06 +08:00
|
|
|
// Changes the format of trace files. Returns false if the format is unrecognized. No longer safe to call after a call
|
|
|
|
// to openTraceFile.
|
|
|
|
bool selectTraceFormatter(std::string format);
|
2019-01-30 05:08:47 +08:00
|
|
|
// Returns true iff format is recognized.
|
|
|
|
bool validateTraceFormat(std::string format);
|
2018-12-21 05:51:06 +08:00
|
|
|
|
2018-09-06 06:06:14 +08:00
|
|
|
void addTraceRole(std::string role);
|
|
|
|
void removeTraceRole(std::string role);
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
enum trace_clock_t { TRACE_CLOCK_NOW, TRACE_CLOCK_REALTIME };
|
|
|
|
extern trace_clock_t g_trace_clock;
|
|
|
|
extern TraceBatch g_traceBatch;
|
|
|
|
|
|
|
|
#endif
|