1
+ /* *
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0.
4
+ */
5
+
6
+ #include < aws/core/client/AWSClient.h>
7
+ #include < aws/core/monitoring/CoreMetrics.h>
8
+ #include < aws/core/monitoring/HttpClientMetrics.h>
9
+ #include < aws/core/monitoring/MonitoringInterface.h>
10
+ #include < aws/core/utils/Array.h>
11
+ #include < aws/core/utils/DateTime.h>
12
+ #include < aws/core/utils/StringUtils.h>
13
+ #include < aws/core/utils/json/JsonSerializer.h>
14
+ #include < aws/core/utils/memory/AWSMemory.h>
15
+ #include < aws/core/utils/memory/stl/AWSMap.h>
16
+ #include < aws/core/utils/memory/stl/AWSSet.h>
17
+ #include < aws/core/utils/memory/stl/AWSString.h>
18
+ #include < aws/core/utils/memory/stl/AWSVector.h>
19
+ #include < performance_tests/reporting/JsonReportingMetrics.h>
20
+
21
+ #include < cstddef>
22
+ #include < cstdint>
23
+ #include < fstream>
24
+ #include < memory>
25
+ #include < utility>
26
+
27
+ using namespace PerformanceTest ::Reporting;
28
+
29
+ Aws::Vector<std::pair<Aws::String, Aws::String>> JsonReportingMetrics::TestDimensions;
30
+ Aws::Set<Aws::String> JsonReportingMetrics::MonitoredOperations;
31
+ Aws::String JsonReportingMetrics::ProductId = " unknown" ;
32
+ Aws::String JsonReportingMetrics::SdkVersion = " unknown" ;
33
+ Aws::String JsonReportingMetrics::CommitId = " unknown" ;
34
+ Aws::String JsonReportingMetrics::OutputFilename = " performance-test-results.json" ;
35
+
36
+ void JsonReportingMetrics::SetTestContext (const Aws::Vector<std::pair<Aws::String, Aws::String>>& dimensions) {
37
+ TestDimensions = dimensions;
38
+ }
39
+
40
+ void JsonReportingMetrics::RegisterOperationsToMonitor (const Aws::Vector<Aws::String>& operations) {
41
+ MonitoredOperations.clear ();
42
+ for (const auto & operation : operations) {
43
+ MonitoredOperations.insert (operation);
44
+ }
45
+ }
46
+
47
+ void JsonReportingMetrics::SetProductInfo (const Aws::String& productId, const Aws::String& sdkVersion, const Aws::String& commitId) {
48
+ ProductId = productId;
49
+ SdkVersion = sdkVersion;
50
+ CommitId = commitId;
51
+ }
52
+
53
+ void JsonReportingMetrics::SetOutputFilename (const Aws::String& filename) { OutputFilename = filename; }
54
+
55
+ JsonReportingMetrics::~JsonReportingMetrics () { DumpJson (); }
56
+
57
+ Aws::UniquePtr<Aws::Monitoring::MonitoringInterface> JsonReportingMetricsFactory::CreateMonitoringInstance () const {
58
+ return Aws::MakeUnique<JsonReportingMetrics>(" JsonReportingMetrics" );
59
+ }
60
+
61
+ void JsonReportingMetrics::AddPerformanceRecord (const Aws::String& serviceName, const Aws::String& requestName,
62
+ const Aws::Monitoring::CoreMetricsCollection& metricsFromCore) const {
63
+ // If no operations are registered, monitor all operations. Otherwise, only monitor registered operations
64
+ if (!MonitoredOperations.empty () && MonitoredOperations.find (requestName) == MonitoredOperations.end ()) {
65
+ return ;
66
+ }
67
+
68
+ int64_t durationMs = 0 ;
69
+ Aws::String const latencyKey = Aws::Monitoring::GetHttpClientMetricNameByType (Aws::Monitoring::HttpClientMetricsType::RequestLatency);
70
+
71
+ auto iterator = metricsFromCore.httpClientMetrics .find (latencyKey);
72
+ if (iterator != metricsFromCore.httpClientMetrics .end ()) {
73
+ durationMs = iterator->second ;
74
+ }
75
+
76
+ PerformanceMetricRecord record;
77
+ record.name =
78
+ Aws::Utils::StringUtils::ToLower (serviceName.c_str ()) + " ." + Aws::Utils::StringUtils::ToLower (requestName.c_str ()) + " .latency" ;
79
+ record.description = " Time to complete " + requestName + " operation" ;
80
+ record.unit = " Milliseconds" ;
81
+ record.date = Aws::Utils::DateTime::Now ().Seconds ();
82
+ record.measurements .push_back (durationMs);
83
+ record.dimensions = TestDimensions;
84
+
85
+ m_performanceRecords.push_back (record);
86
+ }
87
+
88
+ void * JsonReportingMetrics::OnRequestStarted (const Aws::String&, const Aws::String&,
89
+ const std::shared_ptr<const Aws::Http::HttpRequest>&) const {
90
+ return nullptr ;
91
+ }
92
+
93
+ void JsonReportingMetrics::OnRequestSucceeded (const Aws::String& serviceName, const Aws::String& requestName,
94
+ const std::shared_ptr<const Aws::Http::HttpRequest>&, const Aws::Client::HttpResponseOutcome&,
95
+ const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void *) const {
96
+ AddPerformanceRecord (serviceName, requestName, metricsFromCore);
97
+ }
98
+
99
+ void JsonReportingMetrics::OnRequestFailed (const Aws::String& serviceName, const Aws::String& requestName,
100
+ const std::shared_ptr<const Aws::Http::HttpRequest>&, const Aws::Client::HttpResponseOutcome&,
101
+ const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void *) const {
102
+ AddPerformanceRecord (serviceName, requestName, metricsFromCore);
103
+ }
104
+
105
+ void JsonReportingMetrics::OnRequestRetry (const Aws::String&, const Aws::String&, const std::shared_ptr<const Aws::Http::HttpRequest>&,
106
+ void *) const {}
107
+
108
+ void JsonReportingMetrics::OnFinish (const Aws::String&, const Aws::String&, const std::shared_ptr<const Aws::Http::HttpRequest>&,
109
+ void *) const {}
110
+
111
+ void JsonReportingMetrics::DumpJson () const {
112
+ if (m_performanceRecords.empty ()) {
113
+ return ;
114
+ }
115
+
116
+ // Group performance records by name and dimensions
117
+ Aws::Map<Aws::String, PerformanceMetricRecord> aggregatedRecords;
118
+
119
+ for (const auto & record : m_performanceRecords) {
120
+ Aws::String key = record.name ;
121
+ for (const auto & dim : record.dimensions ) {
122
+ key += " :" + Aws::String (dim.first ) + " =" + Aws::String (dim.second );
123
+ }
124
+
125
+ if (aggregatedRecords.find (key) == aggregatedRecords.end ()) {
126
+ aggregatedRecords[key] = record;
127
+ } else {
128
+ for (const auto & measurement : record.measurements ) {
129
+ aggregatedRecords[key].measurements .push_back (measurement);
130
+ }
131
+ }
132
+ }
133
+
134
+ // Create the JSON output
135
+ Aws::Utils::Json::JsonValue root;
136
+ root.WithString (" productId" , ProductId);
137
+ root.WithString (" sdkVersion" , SdkVersion);
138
+ root.WithString (" commitId" , CommitId);
139
+
140
+ Aws::Utils::Array<Aws::Utils::Json::JsonValue> results (aggregatedRecords.size ());
141
+ size_t index = 0 ;
142
+
143
+ for (const auto & pair : aggregatedRecords) {
144
+ const auto & record = pair.second ;
145
+ Aws::Utils::Json::JsonValue jsonMetric;
146
+ jsonMetric.WithString (" name" , record.name );
147
+ jsonMetric.WithString (" description" , record.description );
148
+ jsonMetric.WithString (" unit" , record.unit );
149
+ jsonMetric.WithInt64 (" date" , record.date );
150
+
151
+ if (!record.dimensions .empty ()) {
152
+ Aws::Utils::Array<Aws::Utils::Json::JsonValue> dimensionsArray (record.dimensions .size ());
153
+ for (size_t j = 0 ; j < record.dimensions .size (); ++j) {
154
+ Aws::Utils::Json::JsonValue dimension;
155
+ dimension.WithString (" name" , record.dimensions [j].first );
156
+ dimension.WithString (" value" , record.dimensions [j].second );
157
+ dimensionsArray[j] = std::move (dimension);
158
+ }
159
+ jsonMetric.WithArray (" dimensions" , std::move (dimensionsArray));
160
+ }
161
+
162
+ Aws::Utils::Array<Aws::Utils::Json::JsonValue> measurementsArray (record.measurements .size ());
163
+ for (size_t j = 0 ; j < record.measurements .size (); ++j) {
164
+ Aws::Utils::Json::JsonValue measurementValue;
165
+ measurementValue.AsInt64 (record.measurements [j]);
166
+ measurementsArray[j] = std::move (measurementValue);
167
+ }
168
+ jsonMetric.WithArray (" measurements" , std::move (measurementsArray));
169
+
170
+ results[index++] = std::move (jsonMetric);
171
+ }
172
+
173
+ root.WithArray (" results" , std::move (results));
174
+
175
+ std::ofstream outFile (OutputFilename.c_str ());
176
+ if (outFile.is_open ()) {
177
+ outFile << root.View ().WriteReadable ();
178
+ }
179
+ }
0 commit comments