Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
package software.amazon.awssdk.crt.internal;

/**
* @internal
* IoT Device SDK Metrics Structure
*/
public class IoTDeviceSDKMetrics {
private String libraryName;

public IoTDeviceSDKMetrics() {
this.libraryName = "IoTDeviceSDK/Java";
}

public String getLibraryName() {
return libraryName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import software.amazon.awssdk.crt.mqtt5.Mqtt5Client;
import software.amazon.awssdk.crt.mqtt5.Mqtt5ClientOptions;
import software.amazon.awssdk.crt.mqtt5.packets.ConnectPacket;
import software.amazon.awssdk.crt.internal.IoTDeviceSDKMetrics;

import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
Expand Down Expand Up @@ -77,6 +78,7 @@ private static MqttConnectionConfig s_toMqtt3ConnectionConfig(Mqtt5ClientOptions
options.setProtocolOperationTimeoutMs(mqtt5options.getAckTimeoutSeconds() != null
? Math.toIntExact(mqtt5options.getAckTimeoutSeconds()) * 1000
: 0);
options.setMetricsEnabled(mqtt5options.getMetricsEnabled());
return options;
}

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

if (config.getMetricsEnabled()) {
mqttClientConnectionSetMetrics(getNativeHandle(), new IoTDeviceSDKMetrics());
}

if (config.getMinReconnectTimeoutSecs() != 0L && config.getMaxReconnectTimeoutSecs() != 0L) {
mqttClientConnectionSetReconnectTimeout(getNativeHandle(), config.getMinReconnectTimeoutSecs(),
config.getMaxReconnectTimeoutSecs());
Expand Down Expand Up @@ -502,6 +508,9 @@ private static native boolean mqttClientConnectionSetWill(long connection, Strin
private static native void mqttClientConnectionSetLogin(long connection, String username, String password)
throws CrtRuntimeException;

private static native void mqttClientConnectionSetMetrics(long connection, IoTDeviceSDKMetrics metrics)
throws CrtRuntimeException;

private static native void mqttClientConnectionSetReconnectTimeout(long connection, long minTimeout,
long maxTimeout)
throws CrtRuntimeException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ public final class MqttConnectionConfig extends CrtResource {
private HttpProxyOptions proxyOptions;
private Consumer<WebsocketHandshakeTransformArgs> websocketHandshakeTransform;

/* metrics */
private boolean metricsEnabled = true;

public MqttConnectionConfig() {}


Expand Down Expand Up @@ -538,6 +541,24 @@ public Consumer<WebsocketHandshakeTransformArgs> getWebsocketHandshakeTransform(
return websocketHandshakeTransform;
}

/**
* Enables or disables IoT Device SDK metrics collection
*
* @param enabled true to enable metrics, false to disable
*/
public void setMetricsEnabled(boolean enabled) {
this.metricsEnabled = enabled;
}

/**
* Queries whether IoT Device SDK metrics collection is enabled
*
* @return true if metrics are enabled, false if disabled
*/
public boolean getMetricsEnabled() {
return metricsEnabled;
}

/**
* Creates a (shallow) clone of this config object
*
Expand Down Expand Up @@ -567,6 +588,7 @@ public MqttConnectionConfig clone() {
clone.setWebsocketHandshakeTransform(getWebsocketHandshakeTransform());

clone.setReconnectTimeoutSecs(getMinReconnectTimeoutSecs(), getMaxReconnectTimeoutSecs());
clone.setMetricsEnabled(getMetricsEnabled());

// success, bump up the ref count so we can escape the try-with-resources block
clone.addRef();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import software.amazon.awssdk.crt.mqtt5.packets.ConnectPacket;
import software.amazon.awssdk.crt.mqtt.MqttConnectionConfig;
import software.amazon.awssdk.crt.internal.IoTDeviceSDKMetrics;

import java.util.Map;
import java.util.function.Function;
Expand Down Expand Up @@ -45,6 +46,11 @@ public class Mqtt5ClientOptions {
private Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketHandshakeTransform;
private PublishEvents publishEvents;
private TopicAliasingOptions topicAliasingOptions;
// Indicates whether AWS IoT Metrics are enabled for this client, default to true.
// We don't expose this setting in the builder for now.
private IoTDeviceSDKMetrics iotDeviceSDKMetrics;
private boolean metricsEnabled = true;


/**
* Returns the host name of the MQTT server to connect to.
Expand Down Expand Up @@ -263,6 +269,24 @@ public TopicAliasingOptions getTopicAliasingOptions() {
return this.topicAliasingOptions;
}

/**
* Returns whether AWS IoT Device SDK metrics collection is enabled
*
* @return true if metrics are enabled, false otherwise
*/
public boolean getMetricsEnabled() {
return this.metricsEnabled;
}

/**
* Enables or disables IoT Device SDK metrics collection
*
* @param enabled true to enable metrics, false to disable
*/
public void setMetricsEnabled(boolean enabled) {
this.metricsEnabled = enabled;
}

/**
* Creates a Mqtt5ClientOptionsBuilder instance
* @param builder The builder to get the Mqtt5ClientOptions values from
Expand All @@ -289,6 +313,8 @@ public Mqtt5ClientOptions(Mqtt5ClientOptionsBuilder builder) {
this.websocketHandshakeTransform = builder.websocketHandshakeTransform;
this.publishEvents = builder.publishEvents;
this.topicAliasingOptions = builder.topicAliasingOptions;
this.metricsEnabled = builder.metricsEnabled;
this.iotDeviceSDKMetrics = new IoTDeviceSDKMetrics();
}

/*******************************************************************************
Expand Down Expand Up @@ -583,6 +609,7 @@ static final public class Mqtt5ClientOptionsBuilder {
private Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketHandshakeTransform;
private PublishEvents publishEvents;
private TopicAliasingOptions topicAliasingOptions;
private boolean metricsEnabled = true;

/**
* Sets the host name of the MQTT server to connect to.
Expand Down Expand Up @@ -850,6 +877,17 @@ public Mqtt5ClientOptionsBuilder withTopicAliasingOptions(TopicAliasingOptions o
return this;
}

/**
* Enables or disables IoT Device SDK metrics collection
*
* @param enabled true to enable metrics, false to disable
* @return The Mqtt5ClientOptionsBuilder after setting the metrics option
*/
public Mqtt5ClientOptionsBuilder withMetricsEnabled(boolean enabled) {
this.metricsEnabled = enabled;
return this;
}

/**
* Creates a new Mqtt5ClientOptionsBuilder instance
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,14 @@
}
]
},
{
"name": "software.amazon.awssdk.crt.internal.IoTDeviceSDKMetrics",
"fields": [
{
"name": "libraryName"
}
]
},
{
"name": "software.amazon.awssdk.crt.mqtt5.Mqtt5ClientOptions",
"fields": [
Expand Down Expand Up @@ -1306,6 +1314,12 @@
},
{
"name": "topicAliasingOptions"
},
{
"name": "iotDeviceSDKMetrics"
},
{
"name": "metricsEnabled"
}
],
"methods": [
Expand Down
76 changes: 76 additions & 0 deletions src/native/iot_device_sdk_metrics.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <jni.h>

#include "iot_device_sdk_metrics.h"
#include "mqtt5_packets.h"
#include <aws/mqtt/mqtt.h>
#include <crt.h>
#include <java_class_ids.h>

static char s_iot_device_sdk_metrics_string[] = "IoTDeviceSDKMetrics";

void aws_mqtt_iot_sdk_metrics_java_jni_destroy(
JNIEnv *env,
struct aws_allocator *allocator,
struct aws_mqtt_iot_sdk_metrics_java_jni *java_metrics) {
(void)env;

if (!java_metrics) {
return;
}
AWS_LOGF_DEBUG(AWS_LS_MQTT_GENERAL, "id=%p: Destroying IoTDeviceSDKMetrics", (void *)java_metrics);

if (aws_byte_buf_is_valid(&java_metrics->library_name_buf)) {
aws_byte_buf_clean_up(&java_metrics->library_name_buf);
}

aws_mem_release(allocator, java_metrics);
}

struct aws_mqtt_iot_sdk_metrics_java_jni *aws_mqtt_iot_sdk_metrics_java_jni_create_from_java(
JNIEnv *env,
struct aws_allocator *allocator,
jobject java_iot_device_sdk_metrics) {

struct aws_mqtt_iot_sdk_metrics_java_jni *java_metrics =
aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt_iot_sdk_metrics_java_jni));
if (java_metrics == NULL) {
AWS_LOGF_ERROR(
AWS_LS_MQTT_GENERAL, "IoTDeviceSDKMetrics create_from_java: Creating new IoTDeviceSDKMetrics failed");
return NULL;
}

if (aws_get_string_from_jobject(
env,
java_iot_device_sdk_metrics,
iot_device_sdk_metrics_properties.library_name_field_id,
s_iot_device_sdk_metrics_string,
"library name",
&java_metrics->library_name_buf,
&java_metrics->library_name_cursor,
false,
NULL) == AWS_OP_ERR) {
AWS_LOGF_ERROR(AWS_LS_MQTT_GENERAL, "IoTDeviceSDKMetrics create_from_java: No library name found");
goto on_error;
}
java_metrics->metrics.library_name = java_metrics->library_name_cursor;

return java_metrics;

on_error:
/* Clean up */
aws_mqtt_iot_sdk_metrics_java_jni_destroy(env, allocator, java_metrics);
return NULL;
}

struct aws_mqtt_iot_sdk_metrics *aws_mqtt_iot_sdk_metrics_java_jni_get_metrics(
struct aws_mqtt_iot_sdk_metrics_java_jni *java_metrics) {
if (java_metrics) {
return &java_metrics->metrics;
} else {
return NULL;
}
}
31 changes: 31 additions & 0 deletions src/native/iot_device_sdk_metrics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#ifndef AWS_JNI_IOT_DEVICE_SDK_METRICS_H
#define AWS_JNI_IOT_DEVICE_SDK_METRICS_H

#include <aws/mqtt/mqtt.h>
#include <crt.h>
#include <jni.h>

struct aws_mqtt_iot_sdk_metrics_java_jni {
struct aws_mqtt_iot_sdk_metrics metrics;
struct aws_byte_buf library_name_buf;
struct aws_byte_cursor library_name_cursor;
};

void aws_mqtt_iot_sdk_metrics_java_jni_destroy(
JNIEnv *env,
struct aws_allocator *allocator,
struct aws_mqtt_iot_sdk_metrics_java_jni *java_metrics);

struct aws_mqtt_iot_sdk_metrics_java_jni *aws_mqtt_iot_sdk_metrics_java_jni_create_from_java(
JNIEnv *env,
struct aws_allocator *allocator,
jobject java_iot_device_sdk_metrics);

struct aws_mqtt_iot_sdk_metrics *aws_mqtt_iot_sdk_metrics_java_jni_get_metrics(
struct aws_mqtt_iot_sdk_metrics_java_jni *java_metrics);

#endif /* AWS_JNI_IOT_DEVICE_SDK_METRICS_H */
23 changes: 23 additions & 0 deletions src/native/java_class_ids.c
Original file line number Diff line number Diff line change
Expand Up @@ -1748,6 +1748,15 @@ static void s_cache_mqtt5_client_options(JNIEnv *env) {
"topicAliasingOptions",
"Lsoftware/amazon/awssdk/crt/mqtt5/TopicAliasingOptions;");
AWS_FATAL_ASSERT(mqtt5_client_options_properties.topic_aliasing_options_field_id);
mqtt5_client_options_properties.metrics_enabled_field_id =
(*env)->GetFieldID(env, mqtt5_client_options_properties.client_options_class, "metricsEnabled", "Z");
AWS_FATAL_ASSERT(mqtt5_client_options_properties.metrics_enabled_field_id);
mqtt5_client_options_properties.iot_device_sdk_metrics_field_id = (*env)->GetFieldID(
env,
mqtt5_client_options_properties.client_options_class,
"iotDeviceSDKMetrics",
"Lsoftware/amazon/awssdk/crt/internal/IoTDeviceSDKMetrics;");
AWS_FATAL_ASSERT(mqtt5_client_options_properties.iot_device_sdk_metrics_field_id);
}

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

struct java_iot_device_sdk_metrics_properties iot_device_sdk_metrics_properties;

static void s_cache_iot_device_sdk_metrics(JNIEnv *env) {
jclass cls = (*env)->FindClass(env, "software/amazon/awssdk/crt/internal/IoTDeviceSDKMetrics");
AWS_FATAL_ASSERT(cls);
iot_device_sdk_metrics_properties.iot_device_sdk_metrics_class = (*env)->NewGlobalRef(env, cls);
AWS_FATAL_ASSERT(iot_device_sdk_metrics_properties.iot_device_sdk_metrics_class);

iot_device_sdk_metrics_properties.library_name_field_id = (*env)->GetFieldID(
env, iot_device_sdk_metrics_properties.iot_device_sdk_metrics_class, "libraryName", "Ljava/lang/String;");
AWS_FATAL_ASSERT(iot_device_sdk_metrics_properties.library_name_field_id);
}

// Update jni-config.json when adding or modifying JNI classes for GraalVM support.
static void s_cache_java_class_ids(void *user_data) {
JNIEnv *env = user_data;
Expand Down Expand Up @@ -2752,6 +2774,7 @@ static void s_cache_java_class_ids(void *user_data) {
s_cache_consumer_properties(env);
s_cache_cognito_login_token_source(env);
s_cache_cognito_credentials_provider(env);
s_cache_iot_device_sdk_metrics(env);
}

static aws_thread_once s_cache_once_init = AWS_THREAD_ONCE_STATIC_INIT;
Expand Down
9 changes: 9 additions & 0 deletions src/native/java_class_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,8 @@ struct java_aws_mqtt5_client_options_properties {
jfieldID publish_events_field_id;
jfieldID lifecycle_events_field_id;
jfieldID topic_aliasing_options_field_id;
jfieldID metrics_enabled_field_id;
jfieldID iot_device_sdk_metrics_field_id;
};
extern struct java_aws_mqtt5_client_options_properties mqtt5_client_options_properties;

Expand Down Expand Up @@ -1107,6 +1109,13 @@ struct java_cognito_credentials_provider_properties {

extern struct java_cognito_credentials_provider_properties cognito_credentials_provider_properties;

/* IoTDeviceSDKMetrics */
struct java_iot_device_sdk_metrics_properties {
jclass iot_device_sdk_metrics_class;
jfieldID library_name_field_id;
};
extern struct java_iot_device_sdk_metrics_properties iot_device_sdk_metrics_properties;

/**
* All functions bound to JNI MUST call this before doing anything else.
* This caches all JNI IDs the first time it is called. Any further calls are no-op; it is thread-safe.
Expand Down
Loading
Loading