diff --git a/crt/aws-c-mqtt b/crt/aws-c-mqtt index 1d512d927..23462ac5e 160000 --- a/crt/aws-c-mqtt +++ b/crt/aws-c-mqtt @@ -1 +1 @@ -Subproject commit 1d512d92709f60b74e2cafa018e69a2e647f28e9 +Subproject commit 23462ac5e7e5bcf5834ac9f827c7f9cbc12d5715 diff --git a/include/aws/crt/mqtt/Mqtt5Client.h b/include/aws/crt/mqtt/Mqtt5Client.h index 82330bbbd..45ed1e23a 100644 --- a/include/aws/crt/mqtt/Mqtt5Client.h +++ b/include/aws/crt/mqtt/Mqtt5Client.h @@ -6,6 +6,7 @@ #include #include #include +#include namespace Aws { @@ -687,6 +688,14 @@ namespace Aws */ Mqtt5ClientOptions &WithPublishReceivedCallback(OnPublishReceivedHandler callback) noexcept; + /** + * Enable AWS IoT metrics, if not set, default to enabled. + * + * @param enabled enable AWS IoT metrics to collect SDK usage data + * @return The ConnectPacket Object after setting the user property + */ + Mqtt5ClientOptions &WithMetricsCollection(bool enabled) noexcept; + /** * Initializes the C aws_mqtt5_client_options from Mqtt5ClientOptions. For internal use * @@ -833,10 +842,14 @@ namespace Aws */ uint32_t m_ackTimeoutSec; + bool m_enableMetrics = true; + Mqtt::IoTDeviceSDKMetrics m_sdkMetrics; + /* Underlying Parameters */ Crt::Allocator *m_allocator; aws_http_proxy_options m_httpProxyOptionsStorage; aws_mqtt5_packet_connect_view m_packetConnectViewStorage; + struct aws_mqtt_iot_sdk_metrics m_metricsStorage; }; } // namespace Mqtt5 diff --git a/include/aws/crt/mqtt/MqttClient.h b/include/aws/crt/mqtt/MqttClient.h index 19b2236a3..db7e838b0 100644 --- a/include/aws/crt/mqtt/MqttClient.h +++ b/include/aws/crt/mqtt/MqttClient.h @@ -85,6 +85,7 @@ namespace Aws * @param socketOptions socket options to use when establishing the connection * @param tlsContext tls context to use with the connection * @param useWebsocket should the connection use websockets or should it use direct mqtt? + * @param enableMetrics enable AWS IoT metrics collection * * @return a new connection object. Connect() will still need to be called after all further * configuration is finished. @@ -94,7 +95,8 @@ namespace Aws uint32_t port, const Io::SocketOptions &socketOptions, const Crt::Io::TlsContext &tlsContext, - bool useWebsocket = false) noexcept; + bool useWebsocket = false, + bool enableMetrics = true) noexcept; /** * Create a new connection object over plain text from the client. The client must outlive @@ -103,6 +105,7 @@ namespace Aws * @param port port to connect to * @param socketOptions socket options to use when establishing the connection * @param useWebsocket should the connection use websockets or should it use direct mqtt? + * @param enableMetrics enable AWS IoT metrics collection * * @return a new connection object. Connect() will still need to be called after all further * configuration is finished. @@ -111,7 +114,8 @@ namespace Aws const char *hostName, uint32_t port, const Io::SocketOptions &socketOptions, - bool useWebsocket = false) noexcept; + bool useWebsocket = false, + bool enableMetrics = true) noexcept; private: aws_mqtt_client *m_client; diff --git a/include/aws/crt/mqtt/MqttTypes.h b/include/aws/crt/mqtt/MqttTypes.h index 5f057a33d..2a95e5b07 100644 --- a/include/aws/crt/mqtt/MqttTypes.h +++ b/include/aws/crt/mqtt/MqttTypes.h @@ -33,6 +33,7 @@ namespace Aws Crt::Io::TlsConnectionOptions tlsConnectionOptions; bool useWebsocket = false; bool useTls = false; + bool enableMetrics = true; Allocator *allocator = nullptr; }; diff --git a/include/aws/crt/mqtt/private/MqttConnectionCore.h b/include/aws/crt/mqtt/private/MqttConnectionCore.h index 827cc9db4..c6979f983 100644 --- a/include/aws/crt/mqtt/private/MqttConnectionCore.h +++ b/include/aws/crt/mqtt/private/MqttConnectionCore.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -372,6 +373,8 @@ namespace Aws bool m_useTls; bool m_useWebsocket; MqttConnectionOperationStatistics m_operationStatistics; + bool m_enableMetrics = true; + IoTDeviceSDKMetrics m_sdkMetrics; Allocator *m_allocator; /** diff --git a/include/aws/crt/mqtt/private/MqttShared.h b/include/aws/crt/mqtt/private/MqttShared.h new file mode 100644 index 000000000..3d8eb6bfa --- /dev/null +++ b/include/aws/crt/mqtt/private/MqttShared.h @@ -0,0 +1,38 @@ +/*! \cond DOXYGEN_PRIVATE +** Hide API from this file in doxygen. Set DOXYGEN_PRIVATE in doxygen +** config to enable this file for doxygen. +*/ +#pragma once +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include + +namespace Aws +{ + namespace Crt + { + namespace Mqtt + { + /** + * @internal + * IoT Device SDK Metrics Structure + */ + struct IoTDeviceSDKMetrics + { + String LibraryName; + + IoTDeviceSDKMetrics() { LibraryName = "IoTDeviceSDK/CPP"; } + + void initializeRawOptions(aws_mqtt_iot_sdk_metrics &raw_options) noexcept + { + raw_options.library_name = ByteCursorFromString(LibraryName); + } + }; + } // namespace Mqtt + } // namespace Crt +} // namespace Aws + +/*! \endcond */ diff --git a/include/aws/iot/Mqtt5Client.h b/include/aws/iot/Mqtt5Client.h index b78f12822..09da82a16 100644 --- a/include/aws/iot/Mqtt5Client.h +++ b/include/aws/iot/Mqtt5Client.h @@ -670,8 +670,8 @@ namespace Aws /* Error */ int m_lastError; + /** Enable AWS IoT Metrics Collection. This is always set to true for now. */ bool m_enableMetricsCollection; - Crt::String m_sdkName = "CPPv2"; Crt::String m_sdkVersion = AWS_CRT_CPP_VERSION; }; diff --git a/include/aws/iot/MqttClient.h b/include/aws/iot/MqttClient.h index 886e25a29..98f7c3047 100644 --- a/include/aws/iot/MqttClient.h +++ b/include/aws/iot/MqttClient.h @@ -34,12 +34,14 @@ namespace Aws * @param port port to connect to * @param socketOptions socket options to use when establishing the connection * @param tlsContext tls context that should be used for all connections sourced from this config + * @param enableMetrics Whether to set AWS IoT Metrics in the MQTT CONNECT packet. Default is True. */ MqttClientConnectionConfig( const Crt::String &endpoint, uint32_t port, const Crt::Io::SocketOptions &socketOptions, - Crt::Io::TlsContext &&tlsContext); + Crt::Io::TlsContext &&tlsContext, + bool enableMetrics); /** * Creates a client configuration for use with making new AWS Iot specific MQTT Connections with web @@ -57,6 +59,7 @@ namespace Aws * @param tlsContext tls context that should be used for all connections sourced from this config * @param interceptor websocket upgrade handshake transformation function * @param proxyOptions proxy configuration options + * @param enableMetrics Whether to set AWS IoT Metrics in the MQTT CONNECT packet. Default is True. */ MqttClientConnectionConfig( const Crt::String &endpoint, @@ -64,7 +67,8 @@ namespace Aws const Crt::Io::SocketOptions &socketOptions, Crt::Io::TlsContext &&tlsContext, Crt::Mqtt::OnWebSocketHandshakeIntercept &&interceptor, - const Crt::Optional &proxyOptions); + const Crt::Optional &proxyOptions, + bool enableMetrics); /** * @return true if the instance is in a valid state, false otherwise. @@ -84,7 +88,8 @@ namespace Aws uint32_t port, const Crt::Io::SocketOptions &socketOptions, Crt::Io::TlsContext &&tlsContext, - const Crt::Optional &proxyOptions); + const Crt::Optional &proxyOptions, + bool enableMetrics); Crt::String m_endpoint; uint32_t m_port; @@ -94,6 +99,7 @@ namespace Aws Crt::String m_username; Crt::String m_password; Crt::Optional m_proxyOptions; + bool m_enableMetricsCollection; int m_lastError; friend class MqttClient; diff --git a/source/iot/Mqtt5Client.cpp b/source/iot/Mqtt5Client.cpp index 18fde4ec4..17e3358af 100644 --- a/source/iot/Mqtt5Client.cpp +++ b/source/iot/Mqtt5Client.cpp @@ -628,6 +628,8 @@ namespace Aws m_options->WithHttpProxyOptions(m_proxyOptions.value()); } + m_options->WithMetricsCollection(m_enableMetricsCollection); + return Crt::Mqtt5::Mqtt5Client::NewMqtt5Client(*m_options, m_allocator); } diff --git a/source/iot/MqttClient.cpp b/source/iot/MqttClient.cpp index daed7385a..392b19268 100644 --- a/source/iot/MqttClient.cpp +++ b/source/iot/MqttClient.cpp @@ -31,9 +31,10 @@ namespace Aws const Crt::String &endpoint, uint32_t port, const Crt::Io::SocketOptions &socketOptions, - Crt::Io::TlsContext &&tlsContext) + Crt::Io::TlsContext &&tlsContext, + bool enableMetrics = true) : m_endpoint(endpoint), m_port(port), m_context(std::move(tlsContext)), m_socketOptions(socketOptions), - m_lastError(0) + m_enableMetricsCollection(enableMetrics), m_lastError(0) { } @@ -43,9 +44,11 @@ namespace Aws const Crt::Io::SocketOptions &socketOptions, Crt::Io::TlsContext &&tlsContext, Crt::Mqtt::OnWebSocketHandshakeIntercept &&interceptor, - const Crt::Optional &proxyOptions) + const Crt::Optional &proxyOptions, + bool enableMetrics = true) : m_endpoint(endpoint), m_port(port), m_context(std::move(tlsContext)), m_socketOptions(socketOptions), - m_webSocketInterceptor(std::move(interceptor)), m_proxyOptions(proxyOptions), m_lastError(0) + m_webSocketInterceptor(std::move(interceptor)), m_proxyOptions(proxyOptions), + m_enableMetricsCollection(enableMetrics), m_lastError(0) { } @@ -54,9 +57,10 @@ namespace Aws uint32_t port, const Crt::Io::SocketOptions &socketOptions, Crt::Io::TlsContext &&tlsContext, - const Crt::Optional &proxyOptions) + const Crt::Optional &proxyOptions, + bool enableMetrics = true) : m_endpoint(endpoint), m_port(port), m_context(std::move(tlsContext)), m_socketOptions(socketOptions), - m_proxyOptions(proxyOptions), m_lastError(0) + m_proxyOptions(proxyOptions), m_enableMetricsCollection(enableMetrics), m_lastError(0) { } @@ -532,7 +536,12 @@ namespace Aws if (!m_websocketConfig) { auto config = MqttClientConnectionConfig( - m_endpoint, port, m_socketOptions, std::move(tlsContext), m_proxyOptions); + m_endpoint, + port, + m_socketOptions, + std::move(tlsContext), + m_proxyOptions, + m_enableMetricsCollection); config.m_username = username; config.m_password = password; return config; @@ -562,7 +571,8 @@ namespace Aws m_socketOptions, std::move(tlsContext), signerTransform, - useWebsocketProxyOptions ? m_websocketConfig->ProxyOptions : m_proxyOptions); + useWebsocketProxyOptions ? m_websocketConfig->ProxyOptions : m_proxyOptions, + m_enableMetricsCollection); config.m_username = username; config.m_password = password; return config; @@ -593,7 +603,12 @@ namespace Aws bool useWebsocket = config.m_webSocketInterceptor.operator bool(); auto newConnection = m_client.NewConnection( - config.m_endpoint.c_str(), config.m_port, config.m_socketOptions, config.m_context, useWebsocket); + config.m_endpoint.c_str(), + config.m_port, + config.m_socketOptions, + config.m_context, + useWebsocket, + config.m_enableMetricsCollection); if (!newConnection) { diff --git a/source/mqtt/Mqtt5Client.cpp b/source/mqtt/Mqtt5Client.cpp index 4d40eb7f1..53867ad58 100644 --- a/source/mqtt/Mqtt5Client.cpp +++ b/source/mqtt/Mqtt5Client.cpp @@ -193,8 +193,10 @@ namespace Aws m_extendedValidationAndFlowControlOptions(AWS_MQTT5_EVAFCO_AWS_IOT_CORE_DEFAULTS), m_offlineQueueBehavior(AWS_MQTT5_COQBT_DEFAULT), m_reconnectionOptions({AWS_EXPONENTIAL_BACKOFF_JITTER_DEFAULT, 0, 0, 0}), m_pingTimeoutMs(0), - m_connackTimeoutMs(0), m_ackTimeoutSec(0), m_allocator(allocator) + m_connackTimeoutMs(0), m_ackTimeoutSec(0), m_enableMetrics(true), m_allocator(allocator) { + m_sdkMetrics = Mqtt::IoTDeviceSDKMetrics(); + m_sdkMetrics.initializeRawOptions(m_metricsStorage); m_socketOptions.SetSocketType(Io::SocketType::Stream); AWS_ZERO_STRUCT(m_packetConnectViewStorage); AWS_ZERO_STRUCT(m_httpProxyOptionsStorage); @@ -241,6 +243,7 @@ namespace Aws raw_options.connack_timeout_ms = m_connackTimeoutMs; raw_options.ack_timeout_seconds = m_ackTimeoutSec; raw_options.topic_aliasing_options = &m_topicAliasingOptions; + raw_options.metrics = m_enableMetrics ? &m_metricsStorage : NULL; return true; } @@ -417,6 +420,12 @@ namespace Aws return *this; } + Mqtt5ClientOptions &Mqtt5ClientOptions::WithMetricsCollection(bool enabled) noexcept + { + m_enableMetrics = enabled; + return *this; + } + } // namespace Mqtt5 } // namespace Crt } // namespace Aws diff --git a/source/mqtt/MqttClient.cpp b/source/mqtt/MqttClient.cpp index 63798bfc4..2c6821a65 100644 --- a/source/mqtt/MqttClient.cpp +++ b/source/mqtt/MqttClient.cpp @@ -70,7 +70,8 @@ namespace Aws uint32_t port, const Io::SocketOptions &socketOptions, const Crt::Io::TlsContext &tlsContext, - bool useWebsocket) noexcept + bool useWebsocket, + bool enableMetrics) noexcept { if (!tlsContext) { @@ -89,6 +90,7 @@ namespace Aws connectionOptions.tlsContext = tlsContext; connectionOptions.tlsConnectionOptions = tlsContext.NewConnectionOptions(); connectionOptions.useWebsocket = useWebsocket; + connectionOptions.enableMetrics = enableMetrics; connectionOptions.useTls = true; connectionOptions.allocator = m_client->allocator; @@ -99,7 +101,8 @@ namespace Aws const char *hostName, uint32_t port, const Io::SocketOptions &socketOptions, - bool useWebsocket) noexcept + bool useWebsocket, + bool enableMetrics) noexcept { MqttConnectionOptions connectionOptions; @@ -108,6 +111,7 @@ namespace Aws connectionOptions.socketOptions = socketOptions; connectionOptions.useWebsocket = useWebsocket; connectionOptions.useTls = false; + connectionOptions.enableMetrics = enableMetrics; connectionOptions.allocator = m_client->allocator; return MqttConnection::s_CreateMqttConnection(m_client, std::move(connectionOptions)); diff --git a/source/mqtt/MqttConnectionCore.cpp b/source/mqtt/MqttConnectionCore.cpp index a360dfd04..30eeba3eb 100644 --- a/source/mqtt/MqttConnectionCore.cpp +++ b/source/mqtt/MqttConnectionCore.cpp @@ -40,8 +40,8 @@ namespace Aws : m_underlyingConnection(nullptr), m_hostName(options.hostName), m_port(options.port), m_tlsContext(std::move(options.tlsContext)), m_tlsOptions(std::move(options.tlsConnectionOptions)), m_socketOptions(std::move(options.socketOptions)), m_onAnyCbData(nullptr), m_useTls(options.useTls), - m_useWebsocket(options.useWebsocket), m_allocator(options.allocator), - m_connection(std::move(connection)) + m_useWebsocket(options.useWebsocket), m_enableMetrics(options.enableMetrics), + m_allocator(options.allocator), m_connection(std::move(connection)) { if (client != nullptr) { @@ -471,6 +471,20 @@ namespace Aws aws_mqtt_client_connection_set_connection_termination_handler( m_underlyingConnection, MqttConnectionCore::s_onConnectionTermination, this); + + if (m_enableMetrics) + { + struct aws_mqtt_iot_sdk_metrics metrics; + m_sdkMetrics.initializeRawOptions(metrics); + if (aws_mqtt_client_connection_set_metrics(m_underlyingConnection, &metrics)) + { + AWS_LOGF_DEBUG(AWS_LS_MQTT_CLIENT, "Failed to set Mqtt Metrics"); + } + } + else if (aws_mqtt_client_connection_set_metrics(m_underlyingConnection, nullptr)) + { + AWS_LOGF_DEBUG(AWS_LS_MQTT_CLIENT, "Failed to set Mqtt Metrics"); + } } else { diff --git a/tests/Mqtt5ClientTest.cpp b/tests/Mqtt5ClientTest.cpp index f2c2cd8cc..a39ebcfaa 100644 --- a/tests/Mqtt5ClientTest.cpp +++ b/tests/Mqtt5ClientTest.cpp @@ -530,6 +530,7 @@ static int s_TestMqtt5DirectConnectionWithBasicAuth(Aws::Crt::Allocator *allocat Mqtt5::Mqtt5ClientOptions mqtt5Options(allocator); mqtt5Options.WithHostName(mqtt5TestVars.m_hostname_string); mqtt5Options.WithPort(mqtt5TestVars.m_port_value); + mqtt5Options.WithMetricsCollection(false); std::shared_ptr packetConnect = Aws::Crt::MakeShared(allocator); @@ -852,6 +853,7 @@ static int s_TestMqtt5WSConnectionWithBasicAuth(Aws::Crt::Allocator *allocator, Mqtt5::Mqtt5ClientOptions mqtt5Options(allocator); mqtt5Options.WithHostName(mqtt5TestVars.m_hostname_string); mqtt5Options.WithPort(mqtt5TestVars.m_port_value); + mqtt5Options.WithMetricsCollection(false); std::shared_ptr packetConnect = Aws::Crt::MakeShared(allocator); diff --git a/tests/MqttClientTest.cpp b/tests/MqttClientTest.cpp index edadcbb3b..8da8aa39d 100644 --- a/tests/MqttClientTest.cpp +++ b/tests/MqttClientTest.cpp @@ -244,7 +244,7 @@ static int s_TestMqtt311DirectConnectionWithBasicAuth(Aws::Crt::Allocator *alloc Aws::Crt::Io::SocketOptions socketOptions; socketOptions.SetConnectTimeoutMs(3000); std::shared_ptr connection = client.NewConnection( - aws_string_c_str(endpoint), (uint32_t)std::stoi(aws_string_c_str(port)), socketOptions, false); + aws_string_c_str(endpoint), (uint32_t)std::stoi(aws_string_c_str(port)), socketOptions, false, false); connection->SetLogin(aws_string_c_str(username), aws_string_c_str(password)); int connectResult = s_ConnectAndDisconnect(connection); ASSERT_SUCCESS(connectResult); @@ -456,7 +456,7 @@ static int s_TestMqtt311WSConnectionWithBasicAuth(Aws::Crt::Allocator *allocator Aws::Crt::Io::SocketOptions socketOptions; socketOptions.SetConnectTimeoutMs(3000); std::shared_ptr connection = client.NewConnection( - aws_string_c_str(endpoint), (uint32_t)std::stoi(aws_string_c_str(port)), socketOptions, true); + aws_string_c_str(endpoint), (uint32_t)std::stoi(aws_string_c_str(port)), socketOptions, true, false); connection->SetLogin(aws_string_c_str(username), aws_string_c_str(password)); int connectResult = s_ConnectAndDisconnect(connection); ASSERT_SUCCESS(connectResult);