CdiReturnStatus UserMetrics::Send()

in src/cdi/cloudwatch_sdk_metrics.cpp [327:425]


CdiReturnStatus UserMetrics::Send(const CloudWatchTransferStats* stats_ptr)
{
    CdiReturnStatus rs = kCdiStatusOk;

    // Create CloudWatchClient dynamically, otherwise AWS-SDK can generate broken pipe exceptions.
    Aws::Client::ClientConfiguration client_config;
    // Set region and create an instance of the CloudWatchClient.
    client_config.region = m_region_str;
    Aws::CloudWatch::CloudWatchClient cw(client_config);

    PutMetricDataRequest request;
    request.SetNamespace(m_namespace_str);

    const Aws::Utils::DateTime timestamp(static_cast<int64_t>(stats_ptr->timestamp_in_ms_since_epoch));
    const char* direction_str = stats_ptr->is_receiver ? "Rx" : "Tx";
    const char* connection_str = stats_ptr->dimension_connection_str;
    const bool high_resolution = stats_ptr->high_resolution;

    AddDatum(request, connection_str, direction_str, high_resolution, timestamp, "DroppedPayloads",
             stats_ptr->count_based_delta_stats.delta_num_payloads_dropped, StandardUnit::Count);
    AddDatum(request, connection_str, direction_str, high_resolution, timestamp, "LatePayloads",
            stats_ptr->count_based_delta_stats.delta_num_payloads_late, StandardUnit::Count);
    AddDatum(request, connection_str, direction_str, high_resolution, timestamp, "Disconnections",
            stats_ptr->count_based_delta_stats.delta_dropped_connection_count, StandardUnit::Count);
    AddDatum(request, connection_str, direction_str, high_resolution, timestamp, "Connected",
             stats_ptr->connected, StandardUnit::None);
    AddDatum(request, connection_str, direction_str, high_resolution, timestamp, "CpuUtilization",
             stats_ptr->cpu_utilization / 100, StandardUnit::Percent);
    AddDatum(request, connection_str, direction_str, high_resolution, timestamp, "ProbeRetries",
            stats_ptr->count_based_delta_stats.delta_probe_command_retry_count, StandardUnit::Count);
    AddDatum(request, connection_str, direction_str, high_resolution, timestamp, "BytesTransferred",
            stats_ptr->count_based_delta_stats.delta_num_bytes_transferred, StandardUnit::Bytes);
    AddDatum(request, connection_str, direction_str, high_resolution, timestamp, "PayloadTimeP50",
            stats_ptr->payload_time_interval_stats.transfer_time_P50, StandardUnit::Microseconds);
    AddDatum(request, connection_str, direction_str, high_resolution, timestamp, "PayloadTimeP90",
            stats_ptr->payload_time_interval_stats.transfer_time_P90, StandardUnit::Microseconds);
    AddDatum(request, connection_str, direction_str, high_resolution, timestamp, "PayloadTimeP99",
            stats_ptr->payload_time_interval_stats.transfer_time_P99, StandardUnit::Microseconds);

    if (0 != stats_ptr->payload_time_interval_stats.transfer_count) {
        AddDatum(request, connection_str, direction_str, high_resolution, timestamp, "PayloadTime",
                 stats_ptr->payload_time_interval_stats.transfer_count,
                 stats_ptr->payload_time_interval_stats.transfer_time_min,
                 stats_ptr->payload_time_interval_stats.transfer_time_max,
                 stats_ptr->payload_time_interval_stats.transfer_time_sum,
                 StandardUnit::Microseconds);
    }

    PutMetricDataOutcome outcome;
    try {
        outcome = cw.PutMetricData(request);
    } catch (...) {
        // Should never get here, but just to be safe catch all exceptions.
        CDI_LOG_THREAD(kLogError, "PutMetricData() failed. Caught an unexpected exception.");
        rs = kCdiStatusCloudWatchThrottling;
    }

    if (kCdiStatusOk == rs && !outcome.IsSuccess()) {
        auto error = outcome.GetError();
        Aws::CloudWatch::CloudWatchErrors err_type = error.GetErrorType();
        if (err_type == Aws::CloudWatch::CloudWatchErrors::THROTTLING) {
            // NOTE: Default limits for PutMetricData() are: 40 KB for HTTP POST requests. PutMetricData can handle
            // 150 transactions per second (TPS), which is the maximum number of operation requests you can make per
            // second without being throttled. You can request a quota increase through AWS.
            CDI_LOG_THREAD(kLogInfo, "PutMetricData() is being throttling by AWS-SDK. Message[%s].",
                           outcome.GetError().GetMessage().c_str());
            rs = kCdiStatusCloudWatchThrottling;
        } else if (err_type == Aws::CloudWatch::CloudWatchErrors::INVALID_CLIENT_TOKEN_ID ||
                   err_type == Aws::CloudWatch::CloudWatchErrors::INVALID_ACCESS_KEY_ID ||
                   err_type == Aws::CloudWatch::CloudWatchErrors::SIGNATURE_DOES_NOT_MATCH ||
                   err_type == Aws::CloudWatch::CloudWatchErrors::MISSING_AUTHENTICATION_TOKEN) {
            // In testing, if the access key is wrong, INVALID_CLIENT_TOKEN_ID is returned. If the secret key is wrong,
            // SIGNATURE_DOES_NOT_MATCH is returned. Added INVALID_ACCESS_KEY_ID to this list too.
            CDI_LOG_THREAD(kLogError, "PutMetricData() failed. Check credentials. ErrorType[%d] Message[%s].",
                           err_type, outcome.GetError().GetMessage().c_str());
            rs = kCdiStatusCloudWatchInvalidCredentials;
        } else if (err_type == Aws::CloudWatch::CloudWatchErrors::INVALID_PARAMETER_COMBINATION ||
                   err_type == Aws::CloudWatch::CloudWatchErrors::INVALID_QUERY_PARAMETER ||
                   err_type == Aws::CloudWatch::CloudWatchErrors::INVALID_PARAMETER_VALUE ||
                   err_type == Aws::CloudWatch::CloudWatchErrors::VALIDATION ||
                   err_type == Aws::CloudWatch::CloudWatchErrors::MISSING_PARAMETER ||
                   err_type == Aws::CloudWatch::CloudWatchErrors::MISSING_REQUIRED_PARAMETER ||
                   err_type == Aws::CloudWatch::CloudWatchErrors::MALFORMED_QUERY_STRING ||
                   err_type == Aws::CloudWatch::CloudWatchErrors::MISSING_ACTION ||
                   err_type == Aws::CloudWatch::CloudWatchErrors::INVALID_ACTION) {
            CDI_LOG_THREAD(kLogError, "PutMetricData() failed. ErrorType[%d] Message[%s].", err_type,
                        outcome.GetError().GetMessage().c_str());
            rs = kCdiStatusFatal;
        } else {
            CDI_LOG_THREAD(kLogError,
                           "PutMetricData() failed. Throttling due to unexpected error. ErrorType[%d] Message[%s].",
                           err_type,
                        outcome.GetError().GetMessage().c_str());
            rs = kCdiStatusCloudWatchThrottling;
        }
    }

    return rs;
}