1+ #include " JsonReportingMetrics.h"
2+ #include < aws/core/utils/json/JsonSerializer.h>
3+ #include < aws/core/utils/StringUtils.h>
4+ #include < aws/core/utils/DateTime.h>
5+ #include < fstream>
6+
7+ JsonReportingMetrics::JsonReportingMetrics () {}
8+
9+ JsonReportingMetrics::~JsonReportingMetrics () {
10+ DumpJson ();
11+ }
12+
13+ JsonReportingMetricsFactory::~JsonReportingMetricsFactory () {}
14+
15+ // And the factory method
16+ Aws::UniquePtr<Aws::Monitoring::MonitoringInterface> JsonReportingMetricsFactory::CreateMonitoringInstance () const {
17+ return Aws::MakeUnique<JsonReportingMetrics>(" JsonReportingMetrics" );
18+ }
19+
20+ void JsonReportingMetrics::AddMetric (const Aws::String& serviceName, const Aws::String& requestName,
21+ const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, bool success) const {
22+ std::lock_guard<std::mutex> lock (m_mutex);
23+
24+ double durationMs = 0.0 ;
25+ Aws::String latencyKey = Aws::Monitoring::GetHttpClientMetricNameByType (Aws::Monitoring::HttpClientMetricsType::RequestLatency);
26+
27+ auto it = metricsFromCore.httpClientMetrics .find (latencyKey);
28+ if (it != metricsFromCore.httpClientMetrics .end ()) {
29+ durationMs = static_cast <double >(it->second );
30+ }
31+
32+ RequestMetric metric;
33+ metric.name = Aws::Utils::StringUtils::ToLower (serviceName.c_str ()) +
34+ Aws::String (" ." ) +
35+ Aws::Utils::StringUtils::ToLower (requestName.c_str ());
36+ metric.description = Aws::String (" Time to complete " ) + metric.name + Aws::String (" operation" );
37+ metric.unit = " Milliseconds" ;
38+ metric.date = Aws::Utils::DateTime::CurrentTimeMillis () / 1000 ;
39+ metric.measurements .push_back (durationMs);
40+
41+ metric.dimensions .push_back (std::make_pair (Aws::String (" Service" ), serviceName));
42+ metric.dimensions .push_back (std::make_pair (Aws::String (" Operation" ), requestName));
43+ metric.publishToCloudWatch = true ;
44+
45+ m_metrics.push_back (metric);
46+ }
47+
48+ void JsonReportingMetrics::AggregateMetrics () const {
49+ // Create finalized metrics from the aggregated data
50+ for (const auto & pair : m_aggregatedMetrics) {
51+ RequestMetric metric;
52+ metric.name = pair.first ;
53+ metric.description = Aws::String (" Time to complete " ) + pair.first + Aws::String (" operation" );
54+ metric.unit = " Milliseconds" ;
55+ metric.date = Aws::Utils::DateTime::CurrentTimeMillis () / 1000 ;
56+ metric.measurements = pair.second ;
57+ metric.publishToCloudWatch = true ;
58+
59+ // Add dimensions (e.g., AWS service name)
60+ size_t dotPos = pair.first .find (' .' );
61+ if (dotPos != Aws::String::npos) {
62+ Aws::String service = pair.first .substr (0 , dotPos);
63+ metric.dimensions .push_back (std::make_pair (Aws::String (" Service" ), service));
64+ }
65+
66+ m_metrics.push_back (metric);
67+ }
68+ }
69+
70+ // Interface Overrides
71+ void * JsonReportingMetrics::OnRequestStarted (const Aws::String&, const Aws::String&,
72+ const std::shared_ptr<const Aws::Http::HttpRequest>&) const {
73+ return nullptr ;
74+ }
75+
76+ void JsonReportingMetrics::OnRequestSucceeded (const Aws::String& serviceName, const Aws::String& requestName,
77+ const std::shared_ptr<const Aws::Http::HttpRequest>&,
78+ const Aws::Client::HttpResponseOutcome& outcome,
79+ const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void *) const {
80+ AddMetric (serviceName, requestName, metricsFromCore, outcome.IsSuccess ());
81+ }
82+
83+ void JsonReportingMetrics::OnRequestFailed (const Aws::String& serviceName, const Aws::String& requestName,
84+ const std::shared_ptr<const Aws::Http::HttpRequest>&,
85+ const Aws::Client::HttpResponseOutcome& outcome,
86+ const Aws::Monitoring::CoreMetricsCollection& metricsFromCore, void *) const {
87+ AddMetric (serviceName, requestName, metricsFromCore, outcome.IsSuccess ());
88+ }
89+
90+ void JsonReportingMetrics::OnFinish (const Aws::String&, const Aws::String&, const std::shared_ptr<const Aws::Http::HttpRequest>&,
91+ void *) const {
92+ }
93+
94+ void JsonReportingMetrics::OnRequestRetry (const Aws::String&, const Aws::String&, const std::shared_ptr<const Aws::Http::HttpRequest>&,
95+ void *) const {
96+ }
97+
98+ void JsonReportingMetrics::DumpJson () const {
99+ std::lock_guard<std::mutex> lock (m_mutex);
100+
101+ if (m_metrics.empty ()) {
102+ return ;
103+ }
104+
105+ Aws::Utils::Json::JsonValue root;
106+
107+ // Add required top-level fields
108+ root.WithString (" productId" , " AWS SDK for C++" );
109+ root.WithString (" sdkVersion" , " 1.0.0" );
110+ root.WithString (" commitId" , " unknown" ); // Consider getting this from CI/CD env variable
111+
112+ Aws::Utils::Array<Aws::Utils::Json::JsonValue> results (m_metrics.size ());
113+
114+ for (size_t i = 0 ; i < m_metrics.size (); ++i) {
115+ Aws::Utils::Json::JsonValue metric;
116+ metric.WithString (" name" , m_metrics[i].name );
117+ metric.WithString (" description" , m_metrics[i].description );
118+ metric.WithString (" unit" , m_metrics[i].unit );
119+ metric.WithInt64 (" date" , m_metrics[i].date );
120+
121+ // Add dimensions if present
122+ if (!m_metrics[i].dimensions .empty ()) {
123+ Aws::Utils::Array<Aws::Utils::Json::JsonValue> dimensionsArray (m_metrics[i].dimensions .size ());
124+ for (size_t j = 0 ; j < m_metrics[i].dimensions .size (); ++j) {
125+ Aws::Utils::Json::JsonValue dimension;
126+ dimension.WithString (" name" , m_metrics[i].dimensions [j].first );
127+ dimension.WithString (" value" , m_metrics[i].dimensions [j].second );
128+ dimensionsArray[j] = std::move (dimension);
129+ }
130+ metric.WithArray (" dimensions" , std::move (dimensionsArray));
131+ }
132+
133+ // Create a JSON array for measurements
134+ Aws::Utils::Array<Aws::Utils::Json::JsonValue> measurementsArray (m_metrics[i].measurements .size ());
135+ for (size_t j = 0 ; j < m_metrics[i].measurements .size (); ++j) {
136+ Aws::Utils::Json::JsonValue measurementValue;
137+ measurementValue.AsDouble (m_metrics[i].measurements [j]);
138+ measurementsArray[j] = std::move (measurementValue);
139+ }
140+ metric.WithArray (" measurements" , std::move (measurementsArray));
141+
142+ results[i] = std::move (metric);
143+ }
144+ root.WithArray (" results" , std::move (results));
145+
146+ // Write to stdout so the performance test runner can capture it
147+ std::cout << root.View ().WriteReadable () << std::endl;
148+
149+ // Save to file
150+ std::ofstream outFile (" perf-results.json" );
151+ if (outFile.is_open ()) {
152+ outFile << root.View ().WriteReadable ();
153+ }
154+ }
0 commit comments