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
|
#pragma once
#include "control.h"
#include "probe.h"
#include <ctype.h>
namespace NLWTrace {
#ifndef LWTRACE_DISABLE
// Box that holds dynamically created probe
// NOTE: must be allocated on heap
template <LWTRACE_TEMPLATE_PARAMS>
class TLWProbe: public IBox, public TUserProbe<LWTRACE_TEMPLATE_ARGS> {
private:
// Storage for strings referenced by TEvent
TString Name;
TString Provider;
TVector<TString> Groups;
TVector<TString> Params;
TVector<TProbeRegistry*> Registries; // Note that we assume that registry lives longer than probe
public:
TLWProbe(const TString& provider, const TString& name, const TVector<TString>& groups, const TVector<TString>& params)
: IBox(true)
, Name(name)
, Provider(provider)
, Groups(groups)
, Params(params)
{
// initialize TProbe
TProbe& probe = this->Probe;
probe.Init();
// initialize TEvent
Y_VERIFY(IsCppIdentifier(Name), "probe '%s' is not C++ identifier", Name.data());
Y_VERIFY(IsCppIdentifier(Provider), "provider '%s' is not C++ identifier in probe %s", Provider.data(), Name.data());
probe.Event.Name = Name.c_str();
Zero(probe.Event.Groups);
probe.Event.Groups[0] = Provider.c_str();
auto i = Groups.begin(), ie = Groups.end();
Y_VERIFY(Groups.size() < LWTRACE_MAX_GROUPS, "too many groups in probe %s", Name.data());
for (size_t n = 1; n < LWTRACE_MAX_GROUPS && i != ie; n++, ++i) {
Y_VERIFY(IsCppIdentifier(*i), "group '%s' is not C++ identifier in probe %s", i->data(), Name.data());
probe.Event.Groups[n] = i->c_str();
}
// initialize TSignature
using TUsrSign = TUserSignature<LWTRACE_TEMPLATE_ARGS>;
Y_VERIFY(TUsrSign::ParamCount == (int)Params.size(), "param count mismatch in probe %s: %d != %d",
Name.data(), int(Params.size()), TUsrSign::ParamCount);
TSignature& signature = probe.Event.Signature;
signature.ParamTypes = TUsrSign::ParamTypes;
Zero(signature.ParamNames);
auto j = Params.begin(), je = Params.end();
for (size_t n = 0; n < LWTRACE_MAX_PARAMS && j != je; n++, ++j) {
Y_VERIFY(IsCppIdentifier(*j), "param '%s' is not C++ identifier in probe %s", j->data(), Name.data());
signature.ParamNames[n] = j->c_str();
}
signature.ParamCount = TUsrSign::ParamCount;
signature.SerializeParamsFunc = &TUsrSign::SerializeParams;
signature.CloneParamsFunc = &TUsrSign::CloneParams;
signature.DestroyParamsFunc = &TUsrSign::DestroyParams;
signature.SerializeToPbFunc = &TUsrSign::SerializeToPb;
signature.DeserializeFromPbFunc = &TUsrSign::DeserializeFromPb;
// register probe in global registry
Register(*Singleton<NLWTrace::TProbeRegistry>());
}
~TLWProbe() {
Unregister();
}
void Register(TProbeRegistry& reg) {
Registries.push_back(®);
reg.AddProbe(TBoxPtr(this)); // NOTE: implied `this' object is created with new operator
}
void Unregister() {
// TODO[serxa]: make sure registry never dies before probe it contain
// TODO[serxa]: make sure probe never dies before TSession that uses it
for (TProbeRegistry* reg : Registries) {
reg->RemoveProbe(&this->Probe);
}
}
TProbe* GetProbe() override {
return &this->Probe;
}
private:
static bool IsCppIdentifier(const TString& str) {
bool first = true;
for (char c : str) {
if (first) {
first = false;
if (!(isalpha(c) || c == '_')) {
return false;
}
} else if (!(isalnum(c) || c == '_')) {
return false;
}
}
return true;
}
};
#endif
}
|