Skip to content

Commit 65e4e97

Browse files
authored
Add IoT Metrics Support (#959)
1 parent 17f67d9 commit 65e4e97

22 files changed

Lines changed: 492 additions & 43 deletions
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
package software.amazon.awssdk.crt.internal;
6+
7+
/**
8+
* @internal
9+
* IoT Device SDK Metrics Structure. Not for external usage.
10+
*/
11+
public class IoTDeviceSDKMetrics {
12+
private String libraryName;
13+
14+
public IoTDeviceSDKMetrics() {
15+
this.libraryName = "IoTDeviceSDK/Java";
16+
}
17+
18+
public String getLibraryName() {
19+
return libraryName;
20+
}
21+
}

src/main/java/software/amazon/awssdk/crt/mqtt/MqttClientConnection.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import software.amazon.awssdk.crt.mqtt5.Mqtt5Client;
1818
import software.amazon.awssdk.crt.mqtt5.Mqtt5ClientOptions;
1919
import software.amazon.awssdk.crt.mqtt5.packets.ConnectPacket;
20+
import software.amazon.awssdk.crt.internal.IoTDeviceSDKMetrics;
2021

2122
import java.util.concurrent.CompletableFuture;
2223
import java.util.function.Consumer;
@@ -77,6 +78,7 @@ private static MqttConnectionConfig s_toMqtt3ConnectionConfig(Mqtt5ClientOptions
7778
options.setProtocolOperationTimeoutMs(mqtt5options.getAckTimeoutSeconds() != null
7879
? Math.toIntExact(mqtt5options.getAckTimeoutSeconds()) * 1000
7980
: 0);
81+
options.setMetricsEnabled(mqtt5options.getMetricsEnabled());
8082
return options;
8183
}
8284

@@ -162,6 +164,10 @@ private void SetupConfig(MqttConnectionConfig config) throws MqttException {
162164
mqttClientConnectionSetLogin(getNativeHandle(), config.getUsername(), config.getPassword());
163165
}
164166

167+
if (config.getMetricsEnabled()) {
168+
mqttClientConnectionSetMetrics(getNativeHandle(), new IoTDeviceSDKMetrics());
169+
}
170+
165171
if (config.getMinReconnectTimeoutSecs() != 0L && config.getMaxReconnectTimeoutSecs() != 0L) {
166172
mqttClientConnectionSetReconnectTimeout(getNativeHandle(), config.getMinReconnectTimeoutSecs(),
167173
config.getMaxReconnectTimeoutSecs());
@@ -502,6 +508,9 @@ private static native boolean mqttClientConnectionSetWill(long connection, Strin
502508
private static native void mqttClientConnectionSetLogin(long connection, String username, String password)
503509
throws CrtRuntimeException;
504510

511+
private static native void mqttClientConnectionSetMetrics(long connection, IoTDeviceSDKMetrics metrics)
512+
throws CrtRuntimeException;
513+
505514
private static native void mqttClientConnectionSetReconnectTimeout(long connection, long minTimeout,
506515
long maxTimeout)
507516
throws CrtRuntimeException;

src/main/java/software/amazon/awssdk/crt/mqtt/MqttConnectionConfig.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ public final class MqttConnectionConfig extends CrtResource {
4646
private HttpProxyOptions proxyOptions;
4747
private Consumer<WebsocketHandshakeTransformArgs> websocketHandshakeTransform;
4848

49+
/* metrics */
50+
private boolean metricsEnabled = true;
51+
4952
public MqttConnectionConfig() {}
5053

5154

@@ -538,6 +541,24 @@ public Consumer<WebsocketHandshakeTransformArgs> getWebsocketHandshakeTransform(
538541
return websocketHandshakeTransform;
539542
}
540543

544+
/**
545+
* Enables or disables IoT Device SDK metrics collection. The metrics includes SDK name, version, and platform.
546+
*
547+
* @param enabled true to enable metrics, false to disable
548+
*/
549+
public void setMetricsEnabled(boolean enabled) {
550+
this.metricsEnabled = enabled;
551+
}
552+
553+
/**
554+
* Queries whether IoT Device SDK metrics collection is enabled
555+
*
556+
* @return true if metrics are enabled, false if disabled
557+
*/
558+
public boolean getMetricsEnabled() {
559+
return metricsEnabled;
560+
}
561+
541562
/**
542563
* Creates a (shallow) clone of this config object
543564
*
@@ -567,6 +588,7 @@ public MqttConnectionConfig clone() {
567588
clone.setWebsocketHandshakeTransform(getWebsocketHandshakeTransform());
568589

569590
clone.setReconnectTimeoutSecs(getMinReconnectTimeoutSecs(), getMaxReconnectTimeoutSecs());
591+
clone.setMetricsEnabled(getMetricsEnabled());
570592

571593
// success, bump up the ref count so we can escape the try-with-resources block
572594
clone.addRef();

src/main/java/software/amazon/awssdk/crt/mqtt5/Mqtt5ClientOptions.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import software.amazon.awssdk.crt.mqtt5.packets.ConnectPacket;
1414
import software.amazon.awssdk.crt.mqtt.MqttConnectionConfig;
15+
import software.amazon.awssdk.crt.internal.IoTDeviceSDKMetrics;
1516

1617
import java.util.Map;
1718
import java.util.function.Function;
@@ -45,6 +46,12 @@ public class Mqtt5ClientOptions {
4546
private Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketHandshakeTransform;
4647
private PublishEvents publishEvents;
4748
private TopicAliasingOptions topicAliasingOptions;
49+
// Indicates whether AWS IoT Metrics are enabled for this client, default to true.
50+
// We don't expose iotDeviceSDKMetrics in the builder, and only allow setting
51+
// metricsEnabled for now.
52+
private boolean metricsEnabled = true;
53+
private IoTDeviceSDKMetrics iotDeviceSDKMetrics;
54+
4855

4956
/**
5057
* Returns the host name of the MQTT server to connect to.
@@ -263,6 +270,24 @@ public TopicAliasingOptions getTopicAliasingOptions() {
263270
return this.topicAliasingOptions;
264271
}
265272

273+
/**
274+
* Returns whether AWS IoT Device SDK metrics collection is enabled
275+
*
276+
* @return true if metrics are enabled, false otherwise
277+
*/
278+
public boolean getMetricsEnabled() {
279+
return this.metricsEnabled;
280+
}
281+
282+
/**
283+
* Enables or disables IoT Device SDK metrics collection. The metrics includes SDK name, version, and platform.
284+
*
285+
* @param enabled true to enable metrics, false to disable
286+
*/
287+
public void setMetricsEnabled(boolean enabled) {
288+
this.metricsEnabled = enabled;
289+
}
290+
266291
/**
267292
* Creates a Mqtt5ClientOptionsBuilder instance
268293
* @param builder The builder to get the Mqtt5ClientOptions values from
@@ -289,6 +314,8 @@ public Mqtt5ClientOptions(Mqtt5ClientOptionsBuilder builder) {
289314
this.websocketHandshakeTransform = builder.websocketHandshakeTransform;
290315
this.publishEvents = builder.publishEvents;
291316
this.topicAliasingOptions = builder.topicAliasingOptions;
317+
this.metricsEnabled = builder.metricsEnabled;
318+
this.iotDeviceSDKMetrics = new IoTDeviceSDKMetrics();
292319
}
293320

294321
/*******************************************************************************
@@ -583,6 +610,7 @@ static final public class Mqtt5ClientOptionsBuilder {
583610
private Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketHandshakeTransform;
584611
private PublishEvents publishEvents;
585612
private TopicAliasingOptions topicAliasingOptions;
613+
private boolean metricsEnabled = true;
586614

587615
/**
588616
* Sets the host name of the MQTT server to connect to.
@@ -850,6 +878,17 @@ public Mqtt5ClientOptionsBuilder withTopicAliasingOptions(TopicAliasingOptions o
850878
return this;
851879
}
852880

881+
/**
882+
* Enables or disables IoT Device SDK metrics collection. The metrics includes SDK name, version, and platform.
883+
*
884+
* @param enabled true to enable metrics, false to disable.
885+
* @return The Mqtt5ClientOptionsBuilder after setting the metrics option
886+
*/
887+
public Mqtt5ClientOptionsBuilder withMetricsEnabled(boolean enabled) {
888+
this.metricsEnabled = enabled;
889+
return this;
890+
}
891+
853892
/**
854893
* Creates a new Mqtt5ClientOptionsBuilder instance
855894
*

src/main/resources/META-INF/native-image/software.amazon.awssdk/crt/aws-crt/jni-config.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,14 @@
12561256
}
12571257
]
12581258
},
1259+
{
1260+
"name": "software.amazon.awssdk.crt.internal.IoTDeviceSDKMetrics",
1261+
"fields": [
1262+
{
1263+
"name": "libraryName"
1264+
}
1265+
]
1266+
},
12591267
{
12601268
"name": "software.amazon.awssdk.crt.mqtt5.Mqtt5ClientOptions",
12611269
"fields": [
@@ -1306,6 +1314,12 @@
13061314
},
13071315
{
13081316
"name": "topicAliasingOptions"
1317+
},
1318+
{
1319+
"name": "iotDeviceSDKMetrics"
1320+
},
1321+
{
1322+
"name": "metricsEnabled"
13091323
}
13101324
],
13111325
"methods": [
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
#include <jni.h>
6+
7+
#include "iot_device_sdk_metrics.h"
8+
#include "mqtt5_packets.h"
9+
#include <aws/mqtt/mqtt.h>
10+
#include <crt.h>
11+
#include <java_class_ids.h>
12+
13+
static char s_iot_device_sdk_metrics_string[] = "IoTDeviceSDKMetrics";
14+
15+
void aws_mqtt_iot_metrics_java_jni_destroy(
16+
JNIEnv *env,
17+
struct aws_allocator *allocator,
18+
struct aws_mqtt_iot_metrics_java_jni *java_metrics) {
19+
(void)env;
20+
21+
if (!java_metrics) {
22+
return;
23+
}
24+
AWS_LOGF_DEBUG(AWS_LS_MQTT_GENERAL, "id=%p: Destroying IoTDeviceSDKMetrics", (void *)java_metrics);
25+
26+
if (aws_byte_buf_is_valid(&java_metrics->library_name_buf)) {
27+
aws_byte_buf_clean_up(&java_metrics->library_name_buf);
28+
}
29+
30+
aws_mem_release(allocator, java_metrics);
31+
}
32+
33+
struct aws_mqtt_iot_metrics_java_jni *aws_mqtt_iot_metrics_java_jni_create_from_java(
34+
JNIEnv *env,
35+
struct aws_allocator *allocator,
36+
jobject java_iot_device_sdk_metrics) {
37+
38+
struct aws_mqtt_iot_metrics_java_jni *java_metrics =
39+
aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt_iot_metrics_java_jni));
40+
if (java_metrics == NULL) {
41+
AWS_LOGF_ERROR(
42+
AWS_LS_MQTT_GENERAL, "IoTDeviceSDKMetrics create_from_java: Creating new IoTDeviceSDKMetrics failed");
43+
return NULL;
44+
}
45+
46+
if (aws_get_string_from_jobject(
47+
env,
48+
java_iot_device_sdk_metrics,
49+
iot_device_sdk_metrics_properties.library_name_field_id,
50+
s_iot_device_sdk_metrics_string,
51+
"library name",
52+
&java_metrics->library_name_buf,
53+
&java_metrics->metrics.library_name,
54+
false,
55+
NULL) == AWS_OP_ERR) {
56+
AWS_LOGF_ERROR(AWS_LS_MQTT_GENERAL, "IoTDeviceSDKMetrics create_from_java: No library name found");
57+
goto on_error;
58+
}
59+
60+
return java_metrics;
61+
62+
on_error:
63+
/* Clean up */
64+
aws_mqtt_iot_metrics_java_jni_destroy(env, allocator, java_metrics);
65+
return NULL;
66+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
#ifndef AWS_JNI_IOT_DEVICE_SDK_METRICS_H
6+
#define AWS_JNI_IOT_DEVICE_SDK_METRICS_H
7+
8+
#include <aws/mqtt/mqtt.h>
9+
#include <crt.h>
10+
#include <jni.h>
11+
12+
struct aws_mqtt_iot_metrics_java_jni {
13+
struct aws_mqtt_iot_metrics metrics;
14+
struct aws_byte_buf library_name_buf;
15+
};
16+
17+
void aws_mqtt_iot_metrics_java_jni_destroy(
18+
JNIEnv *env,
19+
struct aws_allocator *allocator,
20+
struct aws_mqtt_iot_metrics_java_jni *java_metrics);
21+
22+
struct aws_mqtt_iot_metrics_java_jni *aws_mqtt_iot_metrics_java_jni_create_from_java(
23+
JNIEnv *env,
24+
struct aws_allocator *allocator,
25+
jobject java_iot_device_sdk_metrics);
26+
27+
#endif /* AWS_JNI_IOT_DEVICE_SDK_METRICS_H */

src/native/java_class_ids.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,6 +1748,15 @@ static void s_cache_mqtt5_client_options(JNIEnv *env) {
17481748
"topicAliasingOptions",
17491749
"Lsoftware/amazon/awssdk/crt/mqtt5/TopicAliasingOptions;");
17501750
AWS_FATAL_ASSERT(mqtt5_client_options_properties.topic_aliasing_options_field_id);
1751+
mqtt5_client_options_properties.metrics_enabled_field_id =
1752+
(*env)->GetFieldID(env, mqtt5_client_options_properties.client_options_class, "metricsEnabled", "Z");
1753+
AWS_FATAL_ASSERT(mqtt5_client_options_properties.metrics_enabled_field_id);
1754+
mqtt5_client_options_properties.iot_device_sdk_metrics_field_id = (*env)->GetFieldID(
1755+
env,
1756+
mqtt5_client_options_properties.client_options_class,
1757+
"iotDeviceSDKMetrics",
1758+
"Lsoftware/amazon/awssdk/crt/internal/IoTDeviceSDKMetrics;");
1759+
AWS_FATAL_ASSERT(mqtt5_client_options_properties.iot_device_sdk_metrics_field_id);
17511760
}
17521761

17531762
struct java_aws_mqtt5_topic_aliasing_options_properties mqtt5_topic_aliasing_options_properties;
@@ -2635,6 +2644,19 @@ static void s_cache_cognito_credentials_provider(JNIEnv *env) {
26352644
AWS_FATAL_ASSERT(cognito_credentials_provider_properties.create_chained_future_method_id != NULL);
26362645
}
26372646

2647+
struct java_iot_device_sdk_metrics_properties iot_device_sdk_metrics_properties;
2648+
2649+
static void s_cache_iot_device_sdk_metrics(JNIEnv *env) {
2650+
jclass cls = (*env)->FindClass(env, "software/amazon/awssdk/crt/internal/IoTDeviceSDKMetrics");
2651+
AWS_FATAL_ASSERT(cls);
2652+
iot_device_sdk_metrics_properties.iot_device_sdk_metrics_class = (*env)->NewGlobalRef(env, cls);
2653+
AWS_FATAL_ASSERT(iot_device_sdk_metrics_properties.iot_device_sdk_metrics_class);
2654+
2655+
iot_device_sdk_metrics_properties.library_name_field_id = (*env)->GetFieldID(
2656+
env, iot_device_sdk_metrics_properties.iot_device_sdk_metrics_class, "libraryName", "Ljava/lang/String;");
2657+
AWS_FATAL_ASSERT(iot_device_sdk_metrics_properties.library_name_field_id);
2658+
}
2659+
26382660
// Update jni-config.json when adding or modifying JNI classes for GraalVM support.
26392661
static void s_cache_java_class_ids(void *user_data) {
26402662
JNIEnv *env = user_data;
@@ -2752,6 +2774,7 @@ static void s_cache_java_class_ids(void *user_data) {
27522774
s_cache_consumer_properties(env);
27532775
s_cache_cognito_login_token_source(env);
27542776
s_cache_cognito_credentials_provider(env);
2777+
s_cache_iot_device_sdk_metrics(env);
27552778
}
27562779

27572780
static aws_thread_once s_cache_once_init = AWS_THREAD_ONCE_STATIC_INIT;

src/native/java_class_ids.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,8 @@ struct java_aws_mqtt5_client_options_properties {
722722
jfieldID publish_events_field_id;
723723
jfieldID lifecycle_events_field_id;
724724
jfieldID topic_aliasing_options_field_id;
725+
jfieldID metrics_enabled_field_id;
726+
jfieldID iot_device_sdk_metrics_field_id;
725727
};
726728
extern struct java_aws_mqtt5_client_options_properties mqtt5_client_options_properties;
727729

@@ -1107,6 +1109,13 @@ struct java_cognito_credentials_provider_properties {
11071109

11081110
extern struct java_cognito_credentials_provider_properties cognito_credentials_provider_properties;
11091111

1112+
/* IoTDeviceSDKMetrics */
1113+
struct java_iot_device_sdk_metrics_properties {
1114+
jclass iot_device_sdk_metrics_class;
1115+
jfieldID library_name_field_id;
1116+
};
1117+
extern struct java_iot_device_sdk_metrics_properties iot_device_sdk_metrics_properties;
1118+
11101119
/**
11111120
* All functions bound to JNI MUST call this before doing anything else.
11121121
* This caches all JNI IDs the first time it is called. Any further calls are no-op; it is thread-safe.

0 commit comments

Comments
 (0)