Skip to content

Commit ba8f982

Browse files
feat(iot-dev): Make SDK thread names configurable (#1720)
- By default, don't change the existing behavior where threads are given unique prefix/postfix so users can correlate threads to clients - Allow users to opt out of these unique thread names - Allow users to provide custom prefix and postfix to thread names #1715
1 parent e438f2e commit ba8f982

File tree

15 files changed

+287
-54
lines changed

15 files changed

+287
-54
lines changed

iothub/device/iot-device-client/src/main/java/com/microsoft/azure/sdk/iot/device/ClientConfiguration.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
import com.microsoft.azure.sdk.iot.provisioning.security.SecurityProviderSymmetricKey;
1212
import com.microsoft.azure.sdk.iot.provisioning.security.SecurityProviderTpm;
1313
import com.microsoft.azure.sdk.iot.provisioning.security.SecurityProviderX509;
14-
import lombok.AccessLevel;
15-
import lombok.Getter;
16-
import lombok.NonNull;
17-
import lombok.Setter;
14+
import lombok.*;
1815
import lombok.extern.slf4j.Slf4j;
1916

2017
import javax.net.ssl.SSLContext;
@@ -86,6 +83,14 @@ public final class ClientConfiguration
8683
@Setter(AccessLevel.PACKAGE)
8784
private int sendInterval = DEFAULT_SEND_INTERVAL_IN_MILLISECONDS;
8885

86+
@Getter
87+
private String threadNameSuffix = null;
88+
89+
@Getter
90+
private String threadNamePrefix = null;
91+
92+
private boolean useIdentifiableThreadNames = true;
93+
8994
private IotHubAuthenticationProvider authenticationProvider;
9095

9196
/**
@@ -215,6 +220,9 @@ private void setClientOptionValues(ClientOptions clientOptions)
215220
this.amqpOpenDeviceSessionsTimeout = clientOptions != null && clientOptions.getAmqpDeviceSessionTimeout() != 0 ? clientOptions.getAmqpDeviceSessionTimeout() : DEFAULT_AMQP_OPEN_DEVICE_SESSIONS_TIMEOUT_IN_SECONDS;
216221
this.proxySettings = clientOptions != null && clientOptions.getProxySettings() != null ? clientOptions.getProxySettings() : null;
217222
this.sendInterval = clientOptions != null && clientOptions.getSendInterval() != 0 ? clientOptions.getSendInterval() : DEFAULT_SEND_INTERVAL_IN_MILLISECONDS;
223+
this.threadNamePrefix = clientOptions != null ? clientOptions.getThreadNamePrefix() : null;
224+
this.threadNameSuffix = clientOptions != null ? clientOptions.getThreadNameSuffix() : null;
225+
this.useIdentifiableThreadNames = clientOptions == null || clientOptions.isUsingIdentifiableThreadNames();
218226

219227
if (proxySettings != null)
220228
{
@@ -632,6 +640,12 @@ public AuthType getAuthenticationType()
632640
}
633641
}
634642

643+
public boolean isUsingIdentifiableThreadNames()
644+
{
645+
// Using a manually written method here to override the name that Lombok would have given it
646+
return this.useIdentifiableThreadNames;
647+
}
648+
635649
/**
636650
* Sets the device operation timeout
637651
* @param timeout the amount of time, in milliseconds, that a given device operation can last before expiring

iothub/device/iot-device-client/src/main/java/com/microsoft/azure/sdk/iot/device/ClientOptions.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,41 @@ public final class ClientOptions
136136
@Getter
137137
@Builder.Default
138138
private final int receiveInterval = RECEIVE_PERIOD_MILLIS;
139+
140+
/**
141+
* The prefix that will be applied to the names of all threads created by this client. If
142+
* {@link #useIdentifiableThreadNames} is set to true, then this value is ignored and this client will create the
143+
* prefix for you.
144+
*/
145+
@Getter
146+
@Builder.Default
147+
private final String threadNamePrefix = null;
148+
149+
/**
150+
* The suffix that will be applied to the names of all threads created by this client. If
151+
* {@link #useIdentifiableThreadNames} is set to true, then this value is ignored and this client will create the
152+
* suffix for you.
153+
*/
154+
@Getter
155+
@Builder.Default
156+
private final String threadNameSuffix = null;
157+
158+
/**
159+
* If true, all threads created by this client will use names that are unique. This is useful in applications that manage
160+
* multiple device/module clients and want to be able to correlate logs to a particular client. In addition,
161+
* the {@link #threadNamePrefix} and {@link #threadNameSuffix} values will be ignored.
162+
*
163+
* If false, all threads created by this client will use simple names that describe the thread's purpose, but are
164+
* indistinguishable from the same threads created by a different client instance. However, users may still alter
165+
* these thread names by providing values for the {@link #threadNamePrefix} and {@link #threadNameSuffix}.
166+
*/
167+
@Builder.Default
168+
private final boolean useIdentifiableThreadNames = true;
169+
170+
171+
public boolean isUsingIdentifiableThreadNames()
172+
{
173+
// Using a manually written method here to override the name that Lombok would have given it
174+
return this.useIdentifiableThreadNames;
175+
}
139176
}

iothub/device/iot-device-client/src/main/java/com/microsoft/azure/sdk/iot/device/DeviceIO.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ final class DeviceIO implements IotHubConnectionStatusChangeCallback
6565

6666
this.state = IotHubConnectionStatus.DISCONNECTED;
6767

68-
this.sendTask = new IotHubSendTask(this.transport);
69-
this.receiveTask = new IotHubReceiveTask(this.transport);
70-
this.reconnectTask = new IotHubReconnectTask(this.transport);
68+
this.sendTask = new IotHubSendTask(this.transport, config.isUsingIdentifiableThreadNames(), config.getThreadNamePrefix(), config.getThreadNameSuffix());
69+
this.receiveTask = new IotHubReceiveTask(this.transport, config.isUsingIdentifiableThreadNames(), config.getThreadNamePrefix(), config.getThreadNameSuffix());
70+
this.reconnectTask = new IotHubReconnectTask(this.transport, config.isUsingIdentifiableThreadNames(), config.getThreadNamePrefix(), config.getThreadNameSuffix());
7171
}
7272

7373
DeviceIO(
@@ -76,13 +76,16 @@ final class DeviceIO implements IotHubConnectionStatusChangeCallback
7676
SSLContext sslContext,
7777
ProxySettings proxySettings,
7878
int keepAliveInterval,
79-
int sendInterval)
79+
int sendInterval,
80+
boolean useIdentifiableThreadNames,
81+
String threadNamePrefix,
82+
String threadNameSuffix)
8083
{
8184
this.state = IotHubConnectionStatus.DISCONNECTED;
82-
this.transport = new IotHubTransport(hostName, protocol, sslContext, proxySettings, this, keepAliveInterval, sendInterval);
83-
this.sendTask = new IotHubSendTask(this.transport);
84-
this.receiveTask = new IotHubReceiveTask(this.transport);
85-
this.reconnectTask = new IotHubReconnectTask(this.transport);
85+
this.transport = new IotHubTransport(hostName, protocol, sslContext, proxySettings, this, keepAliveInterval, sendInterval, useIdentifiableThreadNames, threadNamePrefix, threadNameSuffix);
86+
this.sendTask = new IotHubSendTask(this.transport, useIdentifiableThreadNames, threadNamePrefix, threadNameSuffix);
87+
this.receiveTask = new IotHubReceiveTask(this.transport, useIdentifiableThreadNames, threadNamePrefix, threadNameSuffix);
88+
this.reconnectTask = new IotHubReconnectTask(this.transport, useIdentifiableThreadNames, threadNamePrefix, threadNameSuffix);
8689
}
8790

8891
/**

iothub/device/iot-device-client/src/main/java/com/microsoft/azure/sdk/iot/device/MultiplexingClient.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ public MultiplexingClient(String hostName, IotHubClientProtocol protocol, Multip
101101
int sendMessagesPerThread = options != null ? options.getMaxMessagesSentPerSendInterval() : DEFAULT_MAX_MESSAGES_TO_SEND_PER_THREAD;
102102
int keepAliveInterval = options != null ? options.getKeepAliveInterval() : DEFAULT_KEEP_ALIVE_INTERVAL_IN_SECONDS;
103103
int sendInterval = (int) (options != null ? options.getSendInterval() : DEFAULT_SEND_INTERVAL_IN_MILLISECONDS);
104+
String threadNamePrefix = options != null ? options.getThreadNamePrefix() : null;
105+
String threadNameSuffix = options != null ? options.getThreadNameSuffix() : null;
106+
boolean useIdentifiableThreadNames = options == null || options.isUsingIdentifiableThreadNames();
104107

105108
if (sendPeriod < 0)
106109
{
@@ -127,7 +130,7 @@ else if (receivePeriod == 0) //default builder value for this option, signals th
127130

128131
// Optional settings from MultiplexingClientOptions
129132
SSLContext sslContext = options != null ? options.getSslContext() : null;
130-
this.deviceIO = new DeviceIO(hostName, protocol, sslContext, proxySettings, keepAliveInterval, sendInterval);
133+
this.deviceIO = new DeviceIO(hostName, protocol, sslContext, proxySettings, keepAliveInterval, sendInterval, useIdentifiableThreadNames, threadNamePrefix, threadNameSuffix);
131134
this.deviceIO.setMaxNumberOfMessagesSentPerSendThread(sendMessagesPerThread);
132135
this.deviceIO.setSendPeriodInMilliseconds(sendPeriod);
133136
this.deviceIO.setReceivePeriodInMilliseconds(receivePeriod);

iothub/device/iot-device-client/src/main/java/com/microsoft/azure/sdk/iot/device/MultiplexingClientOptions.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,40 @@ public final class MultiplexingClientOptions
6767
@Getter
6868
@Builder.Default
6969
public final int keepAliveInterval = DEFAULT_KEEP_ALIVE_INTERVAL_IN_SECONDS;
70+
71+
/**
72+
* The prefix that will be applied to the names of all threads created by this client. If
73+
* {@link #useIdentifiableThreadNames} is set to true, then this value is ignored and this client will create the
74+
* prefix for you.
75+
*/
76+
@Getter
77+
@Builder.Default
78+
private final String threadNamePrefix = null;
79+
80+
/**
81+
* The suffix that will be applied to the names of all threads created by this client. If
82+
* {@link #useIdentifiableThreadNames} is set to true, then this value is ignored and this client will create the
83+
* suffix for you.
84+
*/
85+
@Getter
86+
@Builder.Default
87+
private final String threadNameSuffix = null;
88+
89+
/**
90+
* If true, all threads created by this client will use names that are unique. This is useful in applications that manage
91+
* multiple device/module clients and want to be able to correlate logs to a particular client. In addition,
92+
* the {@link #threadNamePrefix} and {@link #threadNameSuffix} values will be ignored.
93+
*
94+
* If false, all threads created by this client will use simple names that describe the thread's purpose, but are
95+
* indistinguishable from the same threads created by a different client instance. However, users may still alter
96+
* these thread names by providing values for the {@link #threadNamePrefix} and {@link #threadNameSuffix}.
97+
*/
98+
@Builder.Default
99+
private final boolean useIdentifiableThreadNames = true;
100+
101+
public boolean isUsingIdentifiableThreadNames()
102+
{
103+
// Using a manually written method here to override the name that Lombok would have given it
104+
return this.useIdentifiableThreadNames;
105+
}
70106
}

iothub/device/iot-device-client/src/main/java/com/microsoft/azure/sdk/iot/device/transport/IotHubReceiveTask.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ public final class IotHubReceiveTask implements Runnable
1717
{
1818
private static final String THREAD_NAME = "azure-iot-sdk-IotHubReceiveTask";
1919
private final IotHubTransport transport;
20+
private final String threadNamePrefix;
21+
private final String threadNameSuffix;
22+
private final boolean useIdentifiableThreadNames;
2023

2124
// This lock is used to communicate state between this thread and the IoTHubTransport layer. This thread will
2225
// wait until a message has been received in that layer before continuing. This means that if the transport layer
@@ -25,7 +28,7 @@ public final class IotHubReceiveTask implements Runnable
2528
// layer's responsibility to notify this thread when a message has been received so that this thread can handle it.
2629
private final Semaphore receiveThreadSemaphore;
2730

28-
public IotHubReceiveTask(IotHubTransport transport)
31+
public IotHubReceiveTask(IotHubTransport transport, boolean useIdentifiableThreadNames, String threadNamePrefix, String threadNameSuffix)
2932
{
3033
if (transport == null)
3134
{
@@ -34,13 +37,35 @@ public IotHubReceiveTask(IotHubTransport transport)
3437

3538
this.transport = transport;
3639
this.receiveThreadSemaphore = this.transport.getReceiveThreadSemaphore();
40+
this.useIdentifiableThreadNames = useIdentifiableThreadNames;
41+
this.threadNamePrefix = threadNamePrefix;
42+
this.threadNameSuffix = threadNameSuffix;
3743
}
3844

3945
public void run()
4046
{
41-
String deviceClientId = this.transport.getDeviceClientUniqueIdentifier();
42-
String connectionId = transport.getTransportConnectionId();
43-
String threadName = deviceClientId + "-" + "Cxn" + connectionId + "-" + THREAD_NAME;
47+
String threadName = "";
48+
if (this.useIdentifiableThreadNames)
49+
{
50+
String deviceClientId = this.transport.getDeviceClientUniqueIdentifier();
51+
String connectionId = transport.getTransportConnectionId();
52+
threadName += deviceClientId + "-" + "Cxn" + connectionId + "-" + THREAD_NAME;
53+
}
54+
else
55+
{
56+
if (this.threadNamePrefix != null && !this.threadNamePrefix.isEmpty())
57+
{
58+
threadName += this.threadNamePrefix;
59+
}
60+
61+
threadName += THREAD_NAME;
62+
63+
if (this.threadNameSuffix != null && !this.threadNameSuffix.isEmpty())
64+
{
65+
threadName += this.threadNameSuffix;
66+
}
67+
}
68+
4469
Thread.currentThread().setName(threadName);
4570

4671
try

iothub/device/iot-device-client/src/main/java/com/microsoft/azure/sdk/iot/device/transport/IotHubReconnectTask.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ public final class IotHubReconnectTask implements Runnable
1515
{
1616
private static final String THREAD_NAME = "azure-iot-sdk-IotHubReconnectTask";
1717
private final IotHubTransport transport;
18+
private final String threadNamePrefix;
19+
private final String threadNameSuffix;
20+
private final boolean useIdentifiableThreadNames;
1821

1922
// This lock is used to communicate state between this thread and the IoTHubTransport layer. This thread will
2023
// wait until a disconnection event occurs in that layer before continuing. This means that if the transport layer
2124
// has no connectivity problems, then this thread will do nothing and cost nothing.
2225
private final Semaphore reconnectThreadSemaphore;
2326

24-
public IotHubReconnectTask(IotHubTransport transport)
27+
public IotHubReconnectTask(IotHubTransport transport, boolean useIdentifiableThreadNames, String threadNamePrefix, String threadNameSuffix)
2528
{
2629
if (transport == null)
2730
{
@@ -30,13 +33,35 @@ public IotHubReconnectTask(IotHubTransport transport)
3033

3134
this.transport = transport;
3235
this.reconnectThreadSemaphore = this.transport.getReconnectThreadSemaphore();
36+
this.useIdentifiableThreadNames = useIdentifiableThreadNames;
37+
this.threadNamePrefix = threadNamePrefix;
38+
this.threadNameSuffix = threadNameSuffix;
3339
}
3440

3541
public void run()
3642
{
37-
String deviceClientId = this.transport.getDeviceClientUniqueIdentifier();
38-
String connectionId = transport.getTransportConnectionId();
39-
String threadName = deviceClientId + "-" + "Cxn" + connectionId + "-" + THREAD_NAME;
43+
String threadName = "";
44+
if (this.useIdentifiableThreadNames)
45+
{
46+
String deviceClientId = this.transport.getDeviceClientUniqueIdentifier();
47+
String connectionId = transport.getTransportConnectionId();
48+
threadName += deviceClientId + "-" + "Cxn" + connectionId + "-" + THREAD_NAME;
49+
}
50+
else
51+
{
52+
if (this.threadNamePrefix != null && !this.threadNamePrefix.isEmpty())
53+
{
54+
threadName += this.threadNamePrefix;
55+
}
56+
57+
threadName += THREAD_NAME;
58+
59+
if (this.threadNameSuffix != null && !this.threadNameSuffix.isEmpty())
60+
{
61+
threadName += this.threadNameSuffix;
62+
}
63+
}
64+
4065
Thread.currentThread().setName(threadName);
4166

4267
try

iothub/device/iot-device-client/src/main/java/com/microsoft/azure/sdk/iot/device/transport/IotHubSendTask.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ public final class IotHubSendTask implements Runnable
1616
{
1717
private static final String THREAD_NAME = "azure-iot-sdk-IotHubSendTask";
1818
private final IotHubTransport transport;
19+
private final String threadNamePrefix;
20+
private final String threadNameSuffix;
21+
private final boolean useIdentifiableThreadNames;
1922

2023
// This lock is used to communicate state between this thread and the IoTHubTransport layer. This thread will
2124
// wait until a message or callback is queued in that layer before continuing. This means that if the transport layer
@@ -25,7 +28,7 @@ public final class IotHubSendTask implements Runnable
2528
// so that this thread can handle it.
2629
private final Semaphore sendThreadSemaphore;
2730

28-
public IotHubSendTask(IotHubTransport transport)
31+
public IotHubSendTask(IotHubTransport transport, boolean useIdentifiableThreadNames, String threadNamePrefix, String threadNameSuffix)
2932
{
3033
if (transport == null)
3134
{
@@ -34,13 +37,35 @@ public IotHubSendTask(IotHubTransport transport)
3437

3538
this.transport = transport;
3639
this.sendThreadSemaphore = this.transport.getSendThreadSemaphore();
40+
this.useIdentifiableThreadNames = useIdentifiableThreadNames;
41+
this.threadNamePrefix = threadNamePrefix;
42+
this.threadNameSuffix = threadNameSuffix;
3743
}
3844

3945
public void run()
4046
{
41-
String deviceClientId = this.transport.getDeviceClientUniqueIdentifier();
42-
String connectionId = transport.getTransportConnectionId();
43-
String threadName = deviceClientId + "-" + "Cxn" + connectionId + "-" + THREAD_NAME;
47+
String threadName = "";
48+
if (this.useIdentifiableThreadNames)
49+
{
50+
String deviceClientId = this.transport.getDeviceClientUniqueIdentifier();
51+
String connectionId = transport.getTransportConnectionId();
52+
threadName += deviceClientId + "-" + "Cxn" + connectionId + "-" + THREAD_NAME;
53+
}
54+
else
55+
{
56+
if (this.threadNamePrefix != null && !this.threadNamePrefix.isEmpty())
57+
{
58+
threadName += this.threadNamePrefix;
59+
}
60+
61+
threadName += THREAD_NAME;
62+
63+
if (this.threadNameSuffix != null && !this.threadNameSuffix.isEmpty())
64+
{
65+
threadName += this.threadNameSuffix;
66+
}
67+
}
68+
4469
Thread.currentThread().setName(threadName);
4570

4671
try

0 commit comments

Comments
 (0)