#pragma once
#include "control.h"
#include "event.h"
#include "preprocessor.h"
#include "probe.h"
#include "start.h"
//
// Full documentation: https://wiki.yandex-team.ru/development/poisk/arcadia/library/lwtrace/
//
// Short usage instruction:
//
// 1. Declare probes provider in header file 'probes.h':
// #include <yweb/robot/kiwi/lwtrace/all.h>
// #define MY_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ // name of your provider
// PROBE(MyProbe, GROUPS("MyGroup1", "MyGroup2"), TYPES(), NAMES()) \ // probe specification w/o argiments
// PROBE(MyAnotherProbe, GROUPS("MyGroup2"), TYPES(int, TString), NAMES("arg1", "arg2")) \ // another probe with arguments
// PROBE(MyScopedProbe, GROUPS(), TYPES(ui64, int), NAMES("duration", "stage")) \ // scoped probe with argument
// /**/
// LWTRACE_DECLARE_PROVIDER(MY_PROVIDER)
//
// 2. Define provider in source file 'provider.cpp':
// #include "probes.h"
// LWTRACE_DEFINE_PROVIDER(MY_PROVIDER)
//
// 3. Call probes from provider in your code:
// #include "probes.h"
// int main() {
// GLOBAL_LWPROBE(MY_PROVIDER, MyProbe);
// GLOBAL_LWPROBE(MY_PROVIDER, MyAnotherProbe, 123, stroka);
// ... or ...
// LWTRACE_USING(MY_PROVIDER); // expands into using namespace
// LWPROBE(MyProbe);
// LWPROBE(MyAnotherProbe, 123, stroka);
// }
//
// 4. Attach provider to your monitoring service:
// #include <yweb/robot/kiwi/util/monservice.h>
// #include "probes.h"
// class TMyMonSrvc: public NKiwi::TMonService {
// TMyMonSrvc(TProbeRegistry& probes)
// {
// THolder<NKiwi::TTraceMonPage> tr(new NKiwi::TTraceMonPage());
// tr->GetProbes().AddProbesList(LWTRACE_GET_PROBES(MY_PROVIDER));
// Register(tr.Release());
// }
// };
//
// 5. Compile and run application
//
// 6. Create file 'mysuper.tr' with trace query:
// Blocks { # Log all calls to probes from MyGroup1
// ProbeDesc { Group: "MyGroup1" }
// Action {
// LogAction { LogTimestamp: true }
// }
// }
// Blocks { # Log first 10 calls to MyAnother with arg1 > 1000
// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" }
// Predicate {
// Operators { Type: OT_GT; Param: "arg1"; Value: "1000" }
// }
// Action {
// LogAction { MaxRecords: 10 }
// }
// }
// Blocks { # Start following executon of all 4 blocks each time MyAnotherProbe was called with arg2 == "start"
// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" }
// Predicate {
// Operators { Type: OT_EQ; Param: "arg2"; Value: "start" }
// }
// Action { StartAction {} }
// }
// Blocks { # Stop following executon of all 4 blocks each time MyAnotherProbe was called with arg2 == "stop"
// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" }
// Predicate {
// Operators { Type: OT_EQ; Param: "arg2"; Value: "stop" }
// }
// Action { StopAction {} }
// }
//
// 7. Send trace query to the server with HTTP POST:
// yweb/robot/kiwi/scripts/trace.sh new uniq-id-for-my-trace hostname:monport < mysuper.tr
//
// 8. With browser go to: http://hostname:monport/trace
//
// 9. Delete query from server:
// yweb/robot/kiwi/scripts/trace.sh delete uniq-id-for-my-trace hostname:monport
//
//
// CONFIGURATION AND SUPPORT:
// 1. Turning off all calls to probes.
// Add to project's CMakeLists.txt: add_definitions(-DLWTRACE_DISABLE_PROBES)
//
// 2. Turning off all calls to events.
// Add to project's CMakeLists.txt: add_definitions(-DLWTRACE_DISABLE_EVENTS)
//
// 3. Increasing maximum number of probe parameters:
// Add more lines in FOREACH_PARAMNUM macro definition in preprocessor.h
//
//
// ISSUES
// 1. Note that executors for different blocks are attached in order of their declaration in trace script.
// Executor can be called by a program as soon as it is attached, therefore there is no guarantee that
// all blocks are started simultaneously
//
#ifndef LWTRACE_DISABLE
// Declare user provider (see USAGE INSTRUCTION)
#define LWTRACE_DECLARE_PROVIDER(provider) LWTRACE_DECLARE_PROVIDER_I(provider)
// Define user provider (see USAGE INSTRUCTION)
#define LWTRACE_DEFINE_PROVIDER(provider) LWTRACE_DEFINE_PROVIDER_I(provider)
// Import names from provider
#define LWTRACE_USING(provider) using namespace LWTRACE_GET_NAMESPACE(provider);
// Probes and events list accessor
#define LWTRACE_GET_PROBES(provider) LWTRACE_GET_PROBES_I(provider)
#define LWTRACE_GET_EVENTS(provider) LWTRACE_GET_EVENTS_I(provider)
#ifndef LWTRACE_DISABLE_PROBES
// Call a probe
// NOTE: LWPROBE() should be used in source files only with previous call to LWTRACE_USING(MY_PROVIDER)
// NOTE: in header files GLOBAL_LWPROBE() should be used instead
// NOTE: if lots of calls needed in header file, it's convenient to define/undef the following macro:
// NOTE: #define MY_PROBE(name, ...) GLOBAL_LWPROBE(MY_PROVIDER, name, ## __VA_ARGS__)
#define GLOBAL_LWPROBE(provider, probe, ...) LWPROBE_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), ##__VA_ARGS__)
#define LWPROBE(probe, ...) LWPROBE_I(LWTRACE_GET_NAME(probe), ##__VA_ARGS__)
#define GLOBAL_LWPROBE_ENABLED(provider, probe) LWPROBE_ENABLED_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe))
#define LWPROBE_ENABLED(probe) LWPROBE_ENABLED_I(LWTRACE_GET_NAME(probe))
#define LWPROBE_OBJ(probe, ...) LWPROBE_I(probe, ##__VA_ARGS__)
// Calls a probe when scope is beeing left
// NOTE: arguments are passed by value and stored until scope exit
// NOTE: probe should be declared with first params of type ui64, argument for which is automaticaly generated (duration in microseconds)
// NOTE: *_DURATION() macros take through "..." all arguments except the first one
#define GLOBAL_LWPROBE_DURATION(provider, probe, ...) LWPROBE_DURATION_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_TYPE(probe), lwtrace_scoped_##provider##probe, LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), ##__VA_ARGS__)
#define LWPROBE_DURATION(probe, ...) LWPROBE_DURATION_I(LWTRACE_GET_TYPE(probe), lwtrace_scoped_##probe, LWTRACE_GET_NAME(probe), ##__VA_ARGS__)
// Probe with orbit support
#define GLOBAL_LWTRACK(provider, probe, orbit, ...) LWTRACK_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), orbit, ##__VA_ARGS__)
#define LWTRACK(probe, orbit, ...) LWTRACK_I(LWTRACE_GET_NAME(probe), orbit, ##__VA_ARGS__)
#define LWTRACK_OBJ(probe, orbit, ...) LWTRACK_I(probe, orbit, ##__VA_ARGS__)
#else
#define GLOBAL_LWPROBE(provider, probe, ...)
#define LWPROBE(probe, ...)
#define GLOBAL_LWPROBE_ENABLED(provider, probe) false
#define LWPROBE_ENABLED(probe) false
#define LWPROBE_OBJ(probe, ...) Y_UNUSED(probe)
#define GLOBAL_LWPROBE_DURATION(provider, probe, ...)
#define LWPROBE_DURATION(probe, ...)
#define GLOBAL_LWTRACK(provider, probe, orbit, ...)
#define LWTRACK(probe, orbit, ...)
#define LWTRACK_OBJ(probe, orbit, ...) Y_UNUSED(probe)
#endif
#ifndef LWTRACE_DISABLE_EVENTS
// Call an event
// NOTE: LWEVENT() should be used in source files only with previous call to LWTRACE_USING(MY_PROVIDER)
// NOTE: in header files GLOBAL_LWEVENT() should be used instead
// NOTE: if lots of calls needed in header file, it's convenient to define/undef the following macro:
// NOTE: #define MY_EVENT(name, ...) GLOBAL_LWEVENT(MY_PROVIDER, name, ## __VA_ARGS__)
#define GLOBAL_LWEVENT(provider, event, ...) LWEVENT_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(event), ##__VA_ARGS__)
#define LWEVENT(event, ...) LWEVENT_I(LWTRACE_GET_NAME(event), ##__VA_ARGS__)
#else
#define GLOBAL_LWEVENT(provider, event, ...)
#define LWEVENT(event, ...)
#endif
#else
#define LWTRACE_DECLARE_PROVIDER(provider)
#define LWTRACE_DEFINE_PROVIDER(provider)
#define LWTRACE_USING(provider)
#define LWTRACE_GET_PROBES(provider) NULL
#define LWTRACE_GET_EVENTS(provider) NULL
#define GLOBAL_LWPROBE(provider, probe, ...)
#define LWPROBE(probe, ...)
#define GLOBAL_LWPROBE_ENABLED(provider, probe) false
#define LWPROBE_ENABLED(probe) false
#define GLOBAL_LWPROBE_DURATION(provider, probe, ...)
#define LWPROBE_DURATION(probe, ...)
#define GLOBAL_LWTRACK(provider, probe, orbit, ...)
#define LWTRACK(probe, orbit, ...)
#define GLOBAL_LWEVENT(provider, event, ...)
#define LWEVENT(event, ...)
#endif