aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/unistat/raii.h
blob: f8f46745fe2829cc763a06954f8da4a02603bbdc (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
111
112
113
114
115
116
117
118
119
120
#pragma once

#include "unistat.h"

#include <util/datetime/base.h>
#include <util/generic/noncopyable.h>
#include <util/generic/va_args.h>
#include <util/generic/yexception.h>
#include <util/system/defaults.h>

class TUnistatTimer: public TNonCopyable {
public:
    template <typename T>
    TUnistatTimer(TUnistat& unistat, T&& holename)
        : Started_(Now())
        , HoleName_(ToString(holename))
        , Aggregator_(unistat)
    {
    }

    ~TUnistatTimer() {
        if (!Dismiss_) {
            Aggregator_.PushSignalUnsafe(HoleName_, (Now() - Started_).MillisecondsFloat());
        }
    }

    void Dismiss() noexcept {
        Dismiss_ = true;
    }

    void Accept() noexcept {
        Dismiss_ = false;
    }

private:
    bool Dismiss_{false};
    const TInstant Started_;
    const TString HoleName_;
    TUnistat& Aggregator_;
};

class TUnistatExceptionCounter: public TNonCopyable {
public:
    template <typename T, typename U>
    TUnistatExceptionCounter(TUnistat& unistat, T&& hasExceptionHolename, U&& noExceptionHolename)
        : HasExceptionHoleName_(ToString(hasExceptionHolename))
        , NoExceptionHoleName_(ToString(noExceptionHolename))
        , Aggregator_(unistat)
    {
    }

    template <typename T>
    TUnistatExceptionCounter(TUnistat& unistat, T&& hasExceptionHolename)
        : HasExceptionHoleName_(ToString(hasExceptionHolename))
        , Aggregator_(unistat)
    {
    }

    ~TUnistatExceptionCounter() {
        if (!Dismiss_) {
            if (UncaughtException()) {
                Aggregator_.PushSignalUnsafe(HasExceptionHoleName_, 1.);
            } else if (NoExceptionHoleName_) {
                Aggregator_.PushSignalUnsafe(NoExceptionHoleName_, 1.);
            }
        }
    }

    void Dismiss() noexcept {
        Dismiss_ = true;
    }

    void Accept() noexcept {
        Dismiss_ = false;
    }

private:
    bool Dismiss_{false};
    const TString HasExceptionHoleName_;
    const TString NoExceptionHoleName_;
    TUnistat& Aggregator_;
};

/**
 * @def Y_UNISTAT_TIMER
 *
 * Macro is needed to time scope and push time into aggregator.
 *
 * @code
 * void DoSomethingImportant() {
 *     Y_UNISTAT_TIMER(TUnistat::Instance(), "doing-important-stuff")
 *     // doing something here
 * }
 * @endcode
 */
#define Y_UNISTAT_TIMER(unistat, holeName) \
    ::TUnistatTimer Y_GENERATE_UNIQUE_ID(timer){unistat, holeName};

#define Y_UNISTAT_EXCEPTION_COUNTER_IMPL_2(unistat, hasExceptionHoleName) \
    ::TUnistatExceptionCounter Y_GENERATE_UNIQUE_ID(exceptionCounter){unistat, hasExceptionHoleName};

#define Y_UNISTAT_EXCEPTION_COUNTER_IMPL_3(unistat, hasExceptionHolename, noExceptionHolename) \
    ::TUnistatExceptionCounter Y_GENERATE_UNIQUE_ID(exceptionCounter){unistat, hasExceptionHolename, noExceptionHolename};

#define Y_UNISTAT_EXCEPTION_COUNTER_IMPL_DISPATCHER(_1, _2, _3, NAME, ...) NAME

/**
 * @def Y_UNISTAT_EXCEPTION_COUNTER
 *
 * Macro is needed to check if there was an exception on scope exit or not.
 *
 * @code
 * void DoSomethingThatMayThrowException() {
 *     Y_UNISTAT_EXCEPTION_COUNTER(TUnistat::Instance(), "exception_occured", "no_exception")
 *     Y_UNISTAT_EXCEPTION_COUNTER(TUnistat::Instance(), "wow_exception_occured")
 *     // doing something here
 * }
 * @endcode
 */
#define Y_UNISTAT_EXCEPTION_COUNTER(...) Y_PASS_VA_ARGS(Y_UNISTAT_EXCEPTION_COUNTER_IMPL_DISPATCHER(__VA_ARGS__, Y_UNISTAT_EXCEPTION_COUNTER_IMPL_3, Y_UNISTAT_EXCEPTION_COUNTER_IMPL_2)(__VA_ARGS__))