aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/lwtrace/lwprobe.h
blob: 9149bb8519503c07c2b18341a9a0eb257e54d59c (plain) (blame)
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); 
            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 
}