Stroika Library 3.0d23
 
Loading...
Searching...
No Matches
OperationalStatistics.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
7#include "Stroika/Foundation/Common/GUID.h"
8#include "Stroika/Foundation/Common/Property.h"
12
13#include "OperationalStatistics.h"
14
15using namespace std;
16
17using namespace Stroika::Foundation;
20using namespace Stroika::Foundation::Execution;
21using namespace Stroika::Foundation::Time;
22
23using Memory::BLOB;
25
26using namespace Stroika::Samples::HTMLUI;
27
28// Comment this in to turn on aggressive noisy DbgTrace in this module
29// #define USE_NOISY_TRACE_IN_THIS_MODULE_ 1
30
31// @todo Lose DIGEST code and use new UUID::CreateNew () method when available.
32
33/*
34 ********************************************************************************
35 ***************** OperationalStatisticsMgr::ProcessAPICmd **********************
36 ********************************************************************************
37 */
38OperationalStatisticsMgr::ProcessAPICmd::~ProcessAPICmd ()
39{
40 TimePointSeconds now{Time::GetTickCount ()};
41 sThe.Add_ (Rec_{Rec_::Kind::eAPI, now, now - fStart_});
42}
43
44void OperationalStatisticsMgr::ProcessAPICmd::NoteError ()
45{
46 TimePointSeconds now{Time::GetTickCount ()};
47 sThe.Add_ (Rec_{.fKind = Rec_::Kind::eAPIError, .fAt = now, .fDuration = 0s});
48}
49
50/*
51 ********************************************************************************
52 ****************** OperationalStatisticsMgr::ProcessDBCmd **********************
53 ********************************************************************************
54 */
55OperationalStatisticsMgr::ProcessDBCmd::~ProcessDBCmd ()
56{
57 Time::TimePointSeconds now{Time::GetTickCount ()};
58 sThe.Add_ (Rec_{.fKind = fKind_, .fAt = now, .fDuration = now - fStart_});
59}
60
61void OperationalStatisticsMgr::ProcessDBCmd::NoteError ()
62{
63 Time::TimePointSeconds now{Time::GetTickCount ()};
64 sThe.Add_ (Rec_{.fKind = Rec_::Kind::eDBError, .fAt = now, .fDuration = 0s});
65}
66
67/*
68 ********************************************************************************
69 ***************************** OperationalStatisticsMgr *************************
70 ********************************************************************************
71 */
72void OperationalStatisticsMgr::RecordActiveRunningTasksCount (size_t length)
73{
74 TimePointSeconds now{Time::GetTickCount ()};
75 sThe.Add_ (Rec_{.fKind = Rec_::Kind::eAPIActiveRunningTasks, .fAt = now, .fDuration = 0s, .fLength = length});
76}
77
78void OperationalStatisticsMgr::RecordOpenConnectionCount (size_t length)
79{
80 TimePointSeconds now{Time::GetTickCount ()};
81 sThe.Add_ (Rec_{.fKind = Rec_::Kind::eAPIOpenConnectionCount, .fAt = now, .fDuration = 0s, .fLength = length});
82}
83
84void OperationalStatisticsMgr::RecordProcessingConnectionCount (size_t length)
85{
86 TimePointSeconds now{Time::GetTickCount ()};
87 sThe.Add_ (Rec_{.fKind = Rec_::Kind::eAPIProcessingConnectionCount, .fAt = now, .fDuration = 0s, .fLength = length});
88}
89
90auto OperationalStatisticsMgr::GetStatistics () const -> Statistics
91{
92 Statistics result;
93
94 // hit every entry and just skip those with null events
95 TimePointSeconds skipBefore = Time::GetTickCount () - kLookbackInterval;
96
97 // could optimize slightly and skip a bunch in a row, but not worth the trouble probably
98 Iterable<Rec_> allApplicable = [&] () {
99 lock_guard lk{fMutex_};
100 return Sequence<Rec_>{begin (fRollingHistory_), end (fRollingHistory_)}.Where (
101 [&] (const Rec_& r) { return r.fAt >= skipBefore and r.fKind != Rec_::Kind::eNull; });
102 }();
103
104 {
105 Iterable<DurationSeconds> apiTimes = allApplicable.Map<Iterable<DurationSeconds>> ([] (const Rec_& r) -> optional<DurationSeconds> {
106 if (r.fKind == Rec_::Kind::eAPI)
107 return r.fDuration;
108 return nullopt;
109 });
110 if (not apiTimes.empty ()) {
111 result.fRecentAPI.fMeanDuration = Duration{Math::Mean (apiTimes)};
112 result.fRecentAPI.fMedianDuration = Duration{Math::Median (apiTimes)};
113 result.fRecentAPI.fMaxDuration = Duration{*apiTimes.Max ()};
114 }
115 result.fRecentAPI.fCallsCompleted = static_cast<unsigned int> (apiTimes.length ());
116 result.fRecentAPI.fErrors =
117 static_cast<unsigned int> (allApplicable.Count ([] (const Rec_& r) { return r.fKind == Rec_::Kind::eAPIError; }));
118 }
119 {
120 Iterable<float> activeRunningWSAPITasks = allApplicable.Map<Iterable<float>> ([] (const Rec_& r) -> optional<float> {
121 if (r.fKind == Rec_::Kind::eAPIActiveRunningTasks)
122 return static_cast<float> (r.fLength);
123 return nullopt;
124 });
125 if (not activeRunningWSAPITasks.empty ()) {
126 result.fRecentAPI.fMedianRunningAPITasks = Math::Median (activeRunningWSAPITasks);
127 }
128 }
129 {
130 Iterable<DurationSeconds> dbReadTimes = allApplicable.Map<Iterable<DurationSeconds>> ([] (const Rec_& r) -> optional<DurationSeconds> {
131 if (r.fKind == Rec_::Kind::eDBRead)
132 return r.fDuration;
133 return nullopt;
134 });
135 if (not dbReadTimes.empty ()) {
136 result.fRecentDB.fReadDurationStats =
137 Math::CommonStatistics<Duration>{.fMax = Duration{dbReadTimes.MaxValue ()}, .fMedian = Duration{dbReadTimes.MedianValue ()}};
138 }
139 result.fRecentDB.fReads = static_cast<unsigned int> (dbReadTimes.length ());
140 }
141 {
142 Iterable<DurationSeconds> dbWriteTimes = allApplicable.Map<Iterable<DurationSeconds>> ([] (const Rec_& r) -> optional<DurationSeconds> {
143 if (r.fKind == Rec_::Kind::eDBWrite)
144 return r.fDuration;
145 return nullopt;
146 });
147 if (not dbWriteTimes.empty ()) {
148 result.fRecentDB.fWriteDurationStats =
149 Math::CommonStatistics<Duration>{.fMax = Duration{dbWriteTimes.MaxValue ()}, .fMedian = Duration{dbWriteTimes.MedianValue ()}};
150 }
151 result.fRecentDB.fWrites = static_cast<unsigned int> (dbWriteTimes.length ());
152 }
153 result.fRecentDB.fErrors = static_cast<unsigned int> (allApplicable.Count ([] (const Rec_& r) { return r.fKind == Rec_::Kind::eDBError; }));
154 return result;
155}
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
A generalization of a vector: a container whose elements are keyed by the natural numbers.
nonvirtual RESULT_CONTAINER Where(INCLUDE_PREDICATE &&includeIfTrue) const
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
nonvirtual RESULT_TYPE MaxValue(ArgByValueType< RESULT_TYPE > defaultValue={}) const
nonvirtual optional< T > Max() const
Definition Iterable.inl:989
nonvirtual RESULT_TYPE MedianValue(ArgByValueType< RESULT_TYPE > defaultValue={}) const
nonvirtual size_t length() const
STL-ish alias for size() - really in STL only used in string, I think, but still makes sense as an al...
nonvirtual RESULT_CONTAINER Map(ELEMENT_MAPPER &&elementMapper) const
functional API which iterates over all members of an Iterable, applies a map function to each element...
nonvirtual size_t Count() const
with no args, same as size, with function filter arg, returns number of items that pass.
nonvirtual bool empty() const
Returns true iff size() == 0.
Definition Iterable.inl:309
STL namespace.