From 850a1c2aea75de3b73bb5784416515462ed67c08 Mon Sep 17 00:00:00 2001 From: littleaj <1690572+littleaj@users.noreply.github.com> Date: Thu, 15 Feb 2018 12:50:10 -0800 Subject: [PATCH 1/9] named all our threads. added thread name to loggers. registered CdsProfileFetcher to be shutdown by sdk mechanism. upgraded to Servlet 3.0.1 spec. Added listener to trigger shutdown during undeploy. added undeploy.sh so tests can be written for this scenario. --- .../internal/logger/InternalAgentLogger.java | 3 +- .../docker/DockerContextInitializer.java | 5 +- .../docker/internal/DockerContextPoller.java | 4 +- .../ActiveTransmissionFileSystemOutput.java | 4 ++ .../common/ActiveTransmissionLoader.java | 3 +- .../ActiveTransmissionNetworkOutput.java | 5 +- .../channel/common/ApacheSender42.java | 12 +++- .../common/TransmissionFileSystemOutput.java | 2 +- .../common/TransmissionPolicyManager.java | 5 +- .../channel/common/TransmitterImpl.java | 5 +- .../sampling/AdaptiveTelemetrySampler.java | 5 +- .../internal/logger/InternalLogger.java | 3 +- .../PerformanceCounterContainer.java | 5 +- .../DefaultQuickPulseCoordinator.java | 4 +- .../internal/quickpulse/QuickPulse.java | 4 +- .../shutdown/SDKShutdownActivity.java | 57 ++++++++++++++----- .../Tomcat.7/resources/linux/undeploy.sh | 21 +++++++ web/build.gradle | 2 +- ...icationInsightsServletContextListener.java | 24 ++++++++ .../internal/WebRequestTrackingFilter.java | 2 + .../correlation/AppProfileFetcher.java | 4 +- .../correlation/CdsProfileFetcher.java | 23 ++++++-- .../mocks/MockHttpAsyncClientWrapper.java | 8 +-- 23 files changed, 168 insertions(+), 42 deletions(-) create mode 100644 test/smoke/appServers/Tomcat.7/resources/linux/undeploy.sh create mode 100644 web/src/main/java/com/microsoft/applicationinsights/web/internal/ApplicationInsightsServletContextListener.java diff --git a/agent/src/main/java/com/microsoft/applicationinsights/agent/internal/logger/InternalAgentLogger.java b/agent/src/main/java/com/microsoft/applicationinsights/agent/internal/logger/InternalAgentLogger.java index 6e3f2bbbc1a..37a1b0fbdb5 100644 --- a/agent/src/main/java/com/microsoft/applicationinsights/agent/internal/logger/InternalAgentLogger.java +++ b/agent/src/main/java/com/microsoft/applicationinsights/agent/internal/logger/InternalAgentLogger.java @@ -161,7 +161,8 @@ private static String createMessage(String prefix, String message, Object... arg currentDateAsString = dateFormatter.format(new Date()); } String formattedMessage = String.format(message, args); - String theMessage = String.format("%s %s, %d: %s", prefix, currentDateAsString, Thread.currentThread().getId(), formattedMessage); + final Thread thisThread = Thread.currentThread(); + String theMessage = String.format("%s %s, %d(%s): %s", prefix, currentDateAsString, thisThread.getId(), thisThread.getName(), formattedMessage); return theMessage; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/docker/DockerContextInitializer.java b/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/docker/DockerContextInitializer.java index 3d3a1c199d4..0cfaef210f7 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/docker/DockerContextInitializer.java +++ b/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/docker/DockerContextInitializer.java @@ -23,7 +23,10 @@ import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.extensibility.TelemetryInitializer; -import com.microsoft.applicationinsights.extensibility.initializer.docker.internal.*; +import com.microsoft.applicationinsights.extensibility.initializer.docker.internal.Constants; +import com.microsoft.applicationinsights.extensibility.initializer.docker.internal.DockerContext; +import com.microsoft.applicationinsights.extensibility.initializer.docker.internal.DockerContextPoller; +import com.microsoft.applicationinsights.extensibility.initializer.docker.internal.FileFactory; import com.microsoft.applicationinsights.internal.logger.InternalLogger; import com.microsoft.applicationinsights.internal.util.LocalStringsUtils; import com.microsoft.applicationinsights.telemetry.Telemetry; diff --git a/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/docker/internal/DockerContextPoller.java b/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/docker/internal/DockerContextPoller.java index 30042d6df18..a5c9fff4a68 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/docker/internal/DockerContextPoller.java +++ b/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/docker/internal/DockerContextPoller.java @@ -41,9 +41,9 @@ protected DockerContextPoller(File contextFile, DockerContextFactory dockerConte } public DockerContextPoller(String contextFileDirectory) { + this(new File(contextFileDirectory + "/" + CONTEXT_FILE_NAME), new DockerContextFactory()); this.setDaemon(true); - this.contextFile = new File(contextFileDirectory + "/" + CONTEXT_FILE_NAME); - this.dockerContextFactory = new DockerContextFactory(); + this.setName(DockerContextPoller.class.getSimpleName()); } @Override diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionFileSystemOutput.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionFileSystemOutput.java index f39f32c155c..4d7f58c6816 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionFileSystemOutput.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionFileSystemOutput.java @@ -25,6 +25,7 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import com.google.common.base.Preconditions; import com.microsoft.applicationinsights.internal.channel.TransmissionOutput; @@ -52,10 +53,13 @@ public ActiveTransmissionFileSystemOutput(TransmissionOutput actualOutput, Trans this.transmissionPolicy = transmissionPolicy; threadPool = ThreadPoolUtils.newLimitedThreadPool(1, 3, 20L, 1024); + final String threadNameFmt = String.format("%s-job-%%d", ActiveTransmissionFileSystemOutput.class.getSimpleName()); threadPool.setThreadFactory(new ThreadFactory() { + private AtomicInteger threadId = new AtomicInteger(); @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); + thread.setName(String.format(threadNameFmt, threadId.getAndIncrement())); thread.setDaemon(true); return thread; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionLoader.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionLoader.java index a78f19a3b67..f957657e3ff 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionLoader.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionLoader.java @@ -88,6 +88,7 @@ public ActiveTransmissionLoader(final TransmissionFileSystemOutput fileSystem, this.fileSystem = fileSystem; this.dispatcher = dispatcher; threads = new Thread[numberOfThreads]; + final String threadNameFmt = String.format("%s-worker-%%d", ActiveTransmissionLoader.class.getSimpleName()); for (int i = 0; i < numberOfThreads; ++i) { threads[i] = new Thread(new Runnable() { @Override @@ -130,7 +131,7 @@ public void run() { // TODO: check whether we need to pause after exception } } - }); + }, String.format(threadNameFmt, i)); threads[i].setDaemon(true); }} diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionNetworkOutput.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionNetworkOutput.java index 6043d2f84fa..498c6fe8f74 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionNetworkOutput.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionNetworkOutput.java @@ -25,6 +25,7 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import com.google.common.base.Preconditions; import com.microsoft.applicationinsights.internal.channel.TransmissionOutput; @@ -63,10 +64,12 @@ public ActiveTransmissionNetworkOutput(TransmissionOutput actualOutput, Transmis maxThreads, DEFAULT_REMOVE_IDLE_THREAD_TIMEOUT_IN_SECONDS, maxMessagesInBuffer); + final String threadNameFmt = String.format("%s-job-%%d", ActiveTransmissionNetworkOutput.class.getSimpleName()); outputThreads.setThreadFactory(new ThreadFactory() { + private final AtomicInteger threadId = new AtomicInteger(); @Override public Thread newThread(Runnable r) { - Thread thread = new Thread(r); + Thread thread = new Thread(r, String.format(threadNameFmt, threadId.getAndIncrement())); thread.setDaemon(true); return thread; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ApacheSender42.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ApacheSender42.java index 2cd5c1fc974..e9e608e1ec7 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ApacheSender42.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ApacheSender42.java @@ -37,13 +37,14 @@ */ final class ApacheSender42 implements ApacheSender { - private HttpClient httpClient; + private final PoolingClientConnectionManager cm; + private final HttpClient httpClient; public ApacheSender42() { - PoolingClientConnectionManager cm = new PoolingClientConnectionManager(); + cm = new PoolingClientConnectionManager(); cm.setMaxTotal(DEFAULT_MAX_TOTAL_CONNECTIONS); cm.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE); - + httpClient = new DefaultHttpClient(cm); HttpParams params = httpClient.getParams(); @@ -65,6 +66,11 @@ public void dispose(HttpResponse response) { @Override public void close() { + try { + cm.shutdown(); + } catch (Exception e) { + // chomp + } } @Override diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java index f33b31db680..a83bb91f77b 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java @@ -183,7 +183,7 @@ public Transmission fetchOldestFile() { } try { - Thread.sleep(DELETE_TIMEOUT_ON_FAILURE_IN_MILLS); + TimeUnit.MILLISECONDS.sleep(DELETE_TIMEOUT_ON_FAILURE_IN_MILLS); } catch (InterruptedException e) { break; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionPolicyManager.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionPolicyManager.java index 4583a3b1604..d49d1eb3272 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionPolicyManager.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionPolicyManager.java @@ -26,6 +26,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import com.microsoft.applicationinsights.internal.logger.InternalLogger; @@ -149,10 +150,12 @@ private synchronized void createScheduler() { } threads = new ScheduledThreadPoolExecutor(1); + final String threadNameFmt = String.format("%s-job-%%d", TransmissionPolicyManager.class.getSimpleName()); threads.setThreadFactory(new ThreadFactory() { + private final AtomicInteger threadId = new AtomicInteger(); @Override public Thread newThread(Runnable r) { - Thread thread = new Thread(r); + Thread thread = new Thread(r, String.format(threadNameFmt, threadId.getAndIncrement())); thread.setDaemon(true); return thread; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmitterImpl.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmitterImpl.java index 67ae7a4d5f6..c3723683cd3 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmitterImpl.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmitterImpl.java @@ -26,6 +26,7 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import com.microsoft.applicationinsights.internal.channel.TelemetriesTransmitter; import com.microsoft.applicationinsights.internal.channel.TelemetrySerializer; @@ -135,10 +136,12 @@ public TransmitterImpl(TransmissionDispatcher transmissionDispatcher, TelemetryS semaphore = new Semaphore(MAX_PENDING_SCHEDULE_REQUESTS); threadPool = new ScheduledThreadPoolExecutor(2); + final String threadNameFmt = String.format("%s-job-%%d", TransmitterImpl.class.getSimpleName()); threadPool.setThreadFactory(new ThreadFactory() { + private final AtomicInteger threadId = new AtomicInteger(); @Override public Thread newThread(Runnable r) { - Thread thread = new Thread(r); + Thread thread = new Thread(r, String.format(threadNameFmt, threadId.getAndIncrement())); thread.setDaemon(true); return thread; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/sampling/AdaptiveTelemetrySampler.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/sampling/AdaptiveTelemetrySampler.java index d8db0c9e086..54968953a7e 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/sampling/AdaptiveTelemetrySampler.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/sampling/AdaptiveTelemetrySampler.java @@ -26,6 +26,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import com.microsoft.applicationinsights.channel.TelemetrySampler; @@ -232,10 +233,12 @@ public boolean isSampledIn(Telemetry telemetry) { private void createTimerThread() { threads = new ScheduledThreadPoolExecutor(1); + final String threadNameFmt = String.format("%s-job-%%d", AdaptiveTelemetrySampler.class.getSimpleName()); threads.setThreadFactory(new ThreadFactory() { + private final AtomicInteger threadId = new AtomicInteger(); @Override public Thread newThread(Runnable r) { - Thread thread = new Thread(r); + Thread thread = new Thread(r, String.format(threadNameFmt, threadId.getAndIncrement())); thread.setDaemon(true); return thread; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/logger/InternalLogger.java b/core/src/main/java/com/microsoft/applicationinsights/internal/logger/InternalLogger.java index 7d1aebacef5..9e816e37c25 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/logger/InternalLogger.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/logger/InternalLogger.java @@ -226,7 +226,8 @@ private static String createMessage(String prefix, String message, Object... arg currentDateAsString = dateFormatter.format(new Date()); } String formattedMessage = String.format(message, args); - String theMessage = String.format("%s %s, %d: %s", prefix, currentDateAsString, Thread.currentThread().getId(), formattedMessage); + final Thread thisThread = Thread.currentThread(); + String theMessage = String.format("%s %s, %d(%s): %s", prefix, currentDateAsString, thisThread.getId(), thisThread.getName(), formattedMessage); return theMessage; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java b/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java index b2eca53fac3..71eeccdfc77 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java @@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.ThreadFactory; import com.google.common.base.Preconditions; @@ -259,10 +260,12 @@ public void run() { private void createThreadToCollect() { threads = new ScheduledThreadPoolExecutor(1); + final String threadNameFmt = String.format("%s-job-%%d", PerformanceCounterContainer.class.getSimpleName()); threads.setThreadFactory(new ThreadFactory() { + private final AtomicInteger threadId = new AtomicInteger(); @Override public Thread newThread(Runnable r) { - Thread thread = new Thread(r); + Thread thread = new Thread(r, String.format(threadNameFmt, threadId.getAndIncrement())); thread.setDaemon(true); return thread; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/DefaultQuickPulseCoordinator.java b/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/DefaultQuickPulseCoordinator.java index 61fd8bce88d..86003551076 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/DefaultQuickPulseCoordinator.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/DefaultQuickPulseCoordinator.java @@ -21,6 +21,8 @@ package com.microsoft.applicationinsights.internal.quickpulse; +import java.util.concurrent.TimeUnit; + import com.microsoft.applicationinsights.internal.logger.InternalLogger; /** @@ -59,7 +61,7 @@ public void run() { sleepInMS = sendData(); } try { - Thread.sleep(sleepInMS); + TimeUnit.MILLISECONDS.sleep(sleepInMS); } catch (InterruptedException e) { } } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/QuickPulse.java b/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/QuickPulse.java index ce3b7071eeb..a083bea0db2 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/QuickPulse.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/QuickPulse.java @@ -80,11 +80,11 @@ public void initialize() { coordinator = new DefaultQuickPulseCoordinator(coordinatorInitData); - senderThread = new Thread(quickPulseDataSender); + senderThread = new Thread(quickPulseDataSender, QuickPulseDataSender.class.getSimpleName()); senderThread.setDaemon(true); senderThread.start(); - thread = new Thread(coordinator); + thread = new Thread(coordinator, DefaultQuickPulseCoordinator.class.getSimpleName()); thread.setDaemon(true); thread.start(); diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/shutdown/SDKShutdownActivity.java b/core/src/main/java/com/microsoft/applicationinsights/internal/shutdown/SDKShutdownActivity.java index 80434ddf0cf..da61d3b2c0c 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/shutdown/SDKShutdownActivity.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/shutdown/SDKShutdownActivity.java @@ -21,6 +21,8 @@ package com.microsoft.applicationinsights.internal.shutdown; +import java.io.Closeable; +import java.util.List; import java.util.ArrayList; import java.util.concurrent.TimeUnit; @@ -44,11 +46,12 @@ public enum SDKShutdownActivity { * 1. The class should not throw an exception * 2. The class 'run' method should exit as soon as possible */ - private static class SDKShutdownThread extends Thread { + private static class SDKShutdownAction implements Runnable { private boolean stopped = false; - private final ArrayList fetchers = new ArrayList(); - private final ArrayList stoppables = new ArrayList(); + private final List fetchers = new ArrayList(); + private final List stoppables = new ArrayList(); + private final List closeables = new ArrayList(); public synchronized void register(ChannelFetcher fetcher) { fetchers.add(fetcher); @@ -58,7 +61,8 @@ public synchronized void register(Stoppable stoppable) { stoppables.add(stoppable); } - public SDKShutdownThread() { + public synchronized void register(Closeable closeable) { + closeables.add(closeable); } @Override @@ -71,6 +75,7 @@ public synchronized void run() { try { stopChannels(); stopStoppables(); + closeClosables(); } finally { // As the last step, the SDK gracefully closes the Internal Logger stopInternalLogger(); @@ -118,25 +123,51 @@ private void stopStoppables() { } } } + private void closeClosables() { + for (Closeable c : closeables) { + try { + c.close(); + } catch (ThreadDeath td) { + throw td; + } catch (Throwable t) { + try { + InternalLogger.INSTANCE.error("Failed to close closeable class '%s': %s", c.getClass().getName(), t.toString()); + InternalLogger.INSTANCE.trace("Stack trace: %s", ExceptionUtils.getStackTrace(t)); + } catch (ThreadDeath td2) { + throw td2; + } catch (Throwable t2) { + // chomp + } + } + } + } } - private static volatile SDKShutdownThread shutdownThread; + private static volatile SDKShutdownAction shutdownAction; public void register(ChannelFetcher fetcher) { - getShutdownThread().register(fetcher); + getShutdownAction().register(fetcher); } public void register(Stoppable stoppable) { - getShutdownThread().register(stoppable); + getShutdownAction().register(stoppable); + } + + public void register(Closeable closable) { + getShutdownAction().register(closable); + } + + public void stopAll() { + getShutdownAction().run(); } - private SDKShutdownThread getShutdownThread() { - if (shutdownThread == null) { + private SDKShutdownAction getShutdownAction() { + if (shutdownAction == null) { synchronized (this) { - if (shutdownThread == null) { + if (shutdownAction == null) { try { - shutdownThread = new SDKShutdownThread(); - Runtime.getRuntime().addShutdownHook(shutdownThread); + shutdownAction = new SDKShutdownAction(); + Runtime.getRuntime().addShutdownHook(new Thread(shutdownAction, SDKShutdownActivity.class.getSimpleName())); } catch (Exception e) { InternalLogger.INSTANCE.error("Error while adding shutdown hook in getShutDownThread call"); InternalLogger.INSTANCE.trace("Stack trace generated is %s", ExceptionUtils.getStackTrace(e)); @@ -145,6 +176,6 @@ private SDKShutdownThread getShutdownThread() { } } - return shutdownThread; + return shutdownAction; } } diff --git a/test/smoke/appServers/Tomcat.7/resources/linux/undeploy.sh b/test/smoke/appServers/Tomcat.7/resources/linux/undeploy.sh new file mode 100644 index 00000000000..e0606a1cec1 --- /dev/null +++ b/test/smoke/appServers/Tomcat.7/resources/linux/undeploy.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +if [ -z "$CATALINA_HOME" ]; then + echo "\$CATALINA_HOME not set" >&2 + exit 1 +fi + +if [ -z "$1" ]; then + echo "Nothing given to deploy" + exit 0 +fi + +if [ ! -e $1 ]; then + echo "File '$1' does not exist" >&2 + exit 2 +fi + +WARFILE=`readlink -f $1` +BASEPATH=`basename $WARFILE .war` + +rm $CATALINA_HOME/webapps/$WARFILE \ No newline at end of file diff --git a/web/build.gradle b/web/build.gradle index 59869e84cc0..6da36825c87 100644 --- a/web/build.gradle +++ b/web/build.gradle @@ -36,7 +36,7 @@ dependencies { compile ([group: 'org.apache.httpcomponents', name: 'httpasyncclient', version: '4.1.3']) provided 'com.opensymphony:xwork:2.0.4' // Struts 2 provided 'org.springframework:spring-webmvc:3.1.0.RELEASE' - provided group: 'javax.servlet', name: 'servlet-api', version: '2.5' + provided group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' provided group: 'javax.enterprise', name: 'cdi-api', version: '1.1' // Java EE testCompile group: 'junit', name: 'junit', version: '4.12' testCompile group: 'org.mockito', name: 'mockito-all', version: '1.8.0' diff --git a/web/src/main/java/com/microsoft/applicationinsights/web/internal/ApplicationInsightsServletContextListener.java b/web/src/main/java/com/microsoft/applicationinsights/web/internal/ApplicationInsightsServletContextListener.java new file mode 100644 index 00000000000..3f7ca7e43a0 --- /dev/null +++ b/web/src/main/java/com/microsoft/applicationinsights/web/internal/ApplicationInsightsServletContextListener.java @@ -0,0 +1,24 @@ +package com.microsoft.applicationinsights.web.internal; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; + +import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import com.microsoft.applicationinsights.internal.shutdown.SDKShutdownActivity; +import com.microsoft.applicationinsights.internal.shutdown.Stoppable; + +@WebListener +public class ApplicationInsightsServletContextListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + InternalLogger.INSTANCE.trace("Shutting down threads"); + SDKShutdownActivity.INSTANCE.stopAll(); + } + +} \ No newline at end of file diff --git a/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java b/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java index 6ff3e779ab2..09b2ce86d7c 100644 --- a/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java +++ b/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java @@ -36,6 +36,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.annotation.WebFilter; import com.microsoft.applicationinsights.common.CommonUtils; import com.microsoft.applicationinsights.TelemetryClient; @@ -48,6 +49,7 @@ /** * Created by yonisha on 2/2/2015. */ +@WebFilter public final class WebRequestTrackingFilter implements Filter { private final static String FILTER_NAME = "ApplicationInsightsWebFilter"; private final static String WEB_INF_FOLDER = "WEB-INF/"; diff --git a/web/src/main/java/com/microsoft/applicationinsights/web/internal/correlation/AppProfileFetcher.java b/web/src/main/java/com/microsoft/applicationinsights/web/internal/correlation/AppProfileFetcher.java index 80f294ff8c7..f80cc18d04c 100644 --- a/web/src/main/java/com/microsoft/applicationinsights/web/internal/correlation/AppProfileFetcher.java +++ b/web/src/main/java/com/microsoft/applicationinsights/web/internal/correlation/AppProfileFetcher.java @@ -21,14 +21,16 @@ package com.microsoft.applicationinsights.web.internal.correlation; +import java.io.Closeable; import java.io.IOException; import java.util.concurrent.ExecutionException; + import org.apache.http.ParseException; /** * Retrieves the application profile from storage */ - public interface AppProfileFetcher { + public interface AppProfileFetcher extends Closeable { /** * Fetches the application profile and returns the appId corresponding to the * instrumentation key provided. diff --git a/web/src/main/java/com/microsoft/applicationinsights/web/internal/correlation/CdsProfileFetcher.java b/web/src/main/java/com/microsoft/applicationinsights/web/internal/correlation/CdsProfileFetcher.java index d85daaeb274..9ba7de29ec1 100644 --- a/web/src/main/java/com/microsoft/applicationinsights/web/internal/correlation/CdsProfileFetcher.java +++ b/web/src/main/java/com/microsoft/applicationinsights/web/internal/correlation/CdsProfileFetcher.java @@ -28,6 +28,13 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import com.microsoft.applicationinsights.internal.shutdown.SDKShutdownActivity; +import com.microsoft.applicationinsights.internal.shutdown.Stoppable; + +import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.http.HttpResponse; import org.apache.http.ParseException; import org.apache.http.client.config.RequestConfig; @@ -39,7 +46,7 @@ public class CdsProfileFetcher implements AppProfileFetcher { - private HttpAsyncClient httpClient; + private CloseableHttpAsyncClient httpClient; private String endpointAddress; private static final String ProfileQueryEndpointAppIdFormat = "%s/api/profiles/%s/appId"; private static final String DefaultProfileQueryEndpointAddress = "https://dc.services.visualstudio.com"; @@ -54,11 +61,11 @@ public CdsProfileFetcher() { .setConnectionRequestTimeout(5000) .build(); - this.httpClient = HttpAsyncClients.custom() + setHttpClient(HttpAsyncClients.custom() .setDefaultRequestConfig(requestConfig) - .build(); + .build()); - ((CloseableHttpAsyncClient)this.httpClient).start(); + this.httpClient.start(); this.tasks = new ConcurrentHashMap>(); this.endpointAddress = DefaultProfileQueryEndpointAddress; @@ -108,8 +115,9 @@ public ProfileFetcherResult fetchAppProfile(String instrumentationKey) throws In } } - public void setHttpClient(HttpAsyncClient client) { + public void setHttpClient(CloseableHttpAsyncClient client) { this.httpClient = client; + SDKShutdownActivity.INSTANCE.register(this.httpClient); } public void setEndpointAddress(String endpoint) throws MalformedURLException { @@ -124,4 +132,9 @@ private Future createFetchTask(String instrumentationKey) { HttpGet request = new HttpGet(String.format(ProfileQueryEndpointAppIdFormat, this.endpointAddress, instrumentationKey)); return this.httpClient.execute(request, null); } + + @Override + public void close() throws IOException { + this.httpClient.close(); + } } \ No newline at end of file diff --git a/web/src/test/java/com/microsoft/applicationinsights/web/internal/correlation/mocks/MockHttpAsyncClientWrapper.java b/web/src/test/java/com/microsoft/applicationinsights/web/internal/correlation/mocks/MockHttpAsyncClientWrapper.java index 1df461ed083..c54554fd477 100644 --- a/web/src/test/java/com/microsoft/applicationinsights/web/internal/correlation/mocks/MockHttpAsyncClientWrapper.java +++ b/web/src/test/java/com/microsoft/applicationinsights/web/internal/correlation/mocks/MockHttpAsyncClientWrapper.java @@ -21,9 +21,9 @@ package com.microsoft.applicationinsights.web.internal.correlation.mocks; -import org.apache.http.nio.client.HttpAsyncClient; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.concurrent.FutureCallback; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import static org.mockito.Matchers.*; import static org.mockito.Mockito.mock; @@ -31,7 +31,7 @@ public class MockHttpAsyncClientWrapper { - private final HttpAsyncClient mockClient; + private final CloseableHttpAsyncClient mockClient; private final MockHttpEntity entity; private final MockHttpResponse response; private final MockHttpTask task; @@ -43,7 +43,7 @@ public MockHttpAsyncClientWrapper() { this.task = new MockHttpTask(this.response); - this.mockClient = mock(HttpAsyncClient.class); + this.mockClient = mock(CloseableHttpAsyncClient.class); when(mockClient.execute(any(HttpUriRequest.class), any(FutureCallback.class))).thenReturn(this.task); } @@ -68,7 +68,7 @@ public void setStatusCode(int code) { this.response.setStatusCode(code); } - public HttpAsyncClient getClient() { + public CloseableHttpAsyncClient getClient() { return this.mockClient; } } \ No newline at end of file From 416edd4ccd677ab30ce1271df7fa14d3ee971ccb Mon Sep 17 00:00:00 2001 From: littleaj <1690572+littleaj@users.noreply.github.com> Date: Thu, 22 Feb 2018 12:26:58 -0800 Subject: [PATCH 2/9] fixed compile error; added close() --- .../web/internal/correlation/mocks/MockProfileFetcher.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/src/test/java/com/microsoft/applicationinsights/web/internal/correlation/mocks/MockProfileFetcher.java b/web/src/test/java/com/microsoft/applicationinsights/web/internal/correlation/mocks/MockProfileFetcher.java index 5fc1af582c2..4517d08cba9 100644 --- a/web/src/test/java/com/microsoft/applicationinsights/web/internal/correlation/mocks/MockProfileFetcher.java +++ b/web/src/test/java/com/microsoft/applicationinsights/web/internal/correlation/mocks/MockProfileFetcher.java @@ -21,6 +21,7 @@ package com.microsoft.applicationinsights.web.internal.correlation.mocks; +import java.io.IOException; import java.util.concurrent.ExecutionException; import com.microsoft.applicationinsights.web.internal.correlation.AppProfileFetcher; import com.microsoft.applicationinsights.web.internal.correlation.ProfileFetcherResultTaskStatus; @@ -59,4 +60,9 @@ public int callCount() { public void setResultStatus(ProfileFetcherResultTaskStatus status) { this.status = status; } + + @Override + public void close() throws IOException { + // nop + } } \ No newline at end of file From 9f1fe548cf1146d0780c868c4a2b8b728bcc9d55 Mon Sep 17 00:00:00 2001 From: littleaj <1690572+littleaj@users.noreply.github.com> Date: Thu, 22 Feb 2018 12:29:25 -0800 Subject: [PATCH 3/9] explicitly called a log file (ls wasn't picking the correct one). increased the number of lines to tail from 25 to 50. added option to specify a different log file. added usage on error from tail command. --- .../Tomcat.7/resources/linux/tailLastLog.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/test/smoke/appServers/Tomcat.7/resources/linux/tailLastLog.sh b/test/smoke/appServers/Tomcat.7/resources/linux/tailLastLog.sh index 1942f4d6d6c..ee638d99e2a 100644 --- a/test/smoke/appServers/Tomcat.7/resources/linux/tailLastLog.sh +++ b/test/smoke/appServers/Tomcat.7/resources/linux/tailLastLog.sh @@ -5,11 +5,20 @@ if [ -z "$CATALINA_HOME" ]; then exit 1 fi -NUM_LINES=25 +TODAYS_DATE=`date +%Y-%m-%d` +LOG_FILE=$CATALINA_HOME/logs/catalina.$TODAYS_DATE.log + if [ ! -z "$1" ]; then - NUM_LINES=$1 + LOG_FILE=$1 fi -ls -1td $CATALINA_HOME/logs +NUM_LINES=50 +if [ ! -z "$2" ]; then + NUM_LINES=$2 +fi -tail -n$NUM_LINES `ls -1td $CATALINA_HOME/logs/* | head -n1` \ No newline at end of file +if ! tail -v -n$NUM_LINES $LOG_FILE; then + echo "USAGE: tailLastLog.sh [logfile] [numlines]" + echo " logfile - absolute path to logfile to tail (default=" + echo " numlines - number of lines to taile (default=50)" +fi From 6f092ff412bd81c15cf2b3b9da7fcfaaded993d6 Mon Sep 17 00:00:00 2001 From: littleaj <1690572+littleaj@users.noreply.github.com> Date: Thu, 22 Feb 2018 12:30:20 -0800 Subject: [PATCH 4/9] fixed log messages from undeploy.sh (copy paste error) fixed command --- .../appServers/Tomcat.7/resources/linux/undeploy.sh | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/smoke/appServers/Tomcat.7/resources/linux/undeploy.sh b/test/smoke/appServers/Tomcat.7/resources/linux/undeploy.sh index e0606a1cec1..fd6a522fe96 100644 --- a/test/smoke/appServers/Tomcat.7/resources/linux/undeploy.sh +++ b/test/smoke/appServers/Tomcat.7/resources/linux/undeploy.sh @@ -6,16 +6,13 @@ if [ -z "$CATALINA_HOME" ]; then fi if [ -z "$1" ]; then - echo "Nothing given to deploy" + echo "Nothing given to undeploy" exit 0 fi -if [ ! -e $1 ]; then - echo "File '$1' does not exist" >&2 +if [ ! -e $CATALINA_HOME/webapps/$1 ]; then + echo "WAR File '$1' does not exist" >&2 exit 2 fi -WARFILE=`readlink -f $1` -BASEPATH=`basename $WARFILE .war` - -rm $CATALINA_HOME/webapps/$WARFILE \ No newline at end of file +rm $CATALINA_HOME/webapps/$1 \ No newline at end of file From 34de317347499d95cbb2d5b385aaa88ede1b6a22 Mon Sep 17 00:00:00 2001 From: littleaj <1690572+littleaj@users.noreply.github.com> Date: Thu, 22 Feb 2018 12:31:36 -0800 Subject: [PATCH 5/9] updated docker file to include the package with 'ps' command. change 'ADD' directive to use wildcard. --- .../appServers/Tomcat.7/tomcat7.linux.partial.dockerfile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/smoke/appServers/Tomcat.7/tomcat7.linux.partial.dockerfile b/test/smoke/appServers/Tomcat.7/tomcat7.linux.partial.dockerfile index d7fa81b76be..9d9ae1e6708 100644 --- a/test/smoke/appServers/Tomcat.7/tomcat7.linux.partial.dockerfile +++ b/test/smoke/appServers/Tomcat.7/tomcat7.linux.partial.dockerfile @@ -11,6 +11,9 @@ RUN mkdir /root/docker-stage RUN apt-get update \ && apt-get install -y wget +RUN apt-get install -y procps + + ENV TOMCAT_MAJOR_VERSION 7 ENV TOMCAT_FULL_VERSION 7.0.84 @@ -24,10 +27,9 @@ RUN wget https://archive.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR_VERSION/v$T ENV CATALINA_HOME /opt/apache-tomcat-$TOMCAT_FULL_VERSION ENV CATALINA_BASE /opt/apache-tomcat-$TOMCAT_FULL_VERSION -ADD ./deploy.sh /root/docker-stage/deploy.sh -ADD ./tailLastLog.sh /root/docker-stage/tailLastLog.sh +ADD ./*.sh /root/docker-stage/ EXPOSE 8080 WORKDIR /root/docker-stage -CMD $CATALINA_HOME/bin/catalina.sh run \ No newline at end of file +CMD ./startServer.sh \ No newline at end of file From 0e0d8c68d6d3a5a3a2b34bfb4f8f2f012a0e9c78 Mon Sep 17 00:00:00 2001 From: littleaj <1690572+littleaj@users.noreply.github.com> Date: Thu, 22 Feb 2018 12:31:51 -0800 Subject: [PATCH 6/9] added startServer and stopServer scripts for debugging --- .../appServers/Tomcat.7/resources/linux/startServer.sh | 8 ++++++++ .../appServers/Tomcat.7/resources/linux/stopServer.sh | 8 ++++++++ 2 files changed, 16 insertions(+) create mode 100644 test/smoke/appServers/Tomcat.7/resources/linux/startServer.sh create mode 100644 test/smoke/appServers/Tomcat.7/resources/linux/stopServer.sh diff --git a/test/smoke/appServers/Tomcat.7/resources/linux/startServer.sh b/test/smoke/appServers/Tomcat.7/resources/linux/startServer.sh new file mode 100644 index 00000000000..921a064271f --- /dev/null +++ b/test/smoke/appServers/Tomcat.7/resources/linux/startServer.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ -z "$CATALINA_HOME" ]; then + echo "\$CATALINA_HOME not set" >&2 + exit 1 +fi + +$CATALINA_HOME/bin/catalina.sh run \ No newline at end of file diff --git a/test/smoke/appServers/Tomcat.7/resources/linux/stopServer.sh b/test/smoke/appServers/Tomcat.7/resources/linux/stopServer.sh new file mode 100644 index 00000000000..cdc1e854f57 --- /dev/null +++ b/test/smoke/appServers/Tomcat.7/resources/linux/stopServer.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ -z "$CATALINA_HOME" ]; then + echo "\$CATALINA_HOME not set" >&2 + exit 1 +fi + +$CATALINA_HOME/bin/shutdown.sh \ No newline at end of file From 48105f84eb218c6e348688c53d66877fe2be977e Mon Sep 17 00:00:00 2001 From: littleaj <1690572+littleaj@users.noreply.github.com> Date: Thu, 22 Feb 2018 12:58:56 -0800 Subject: [PATCH 7/9] reverted Thread.sleep changes; superfluous --- .../internal/channel/common/TransmissionFileSystemOutput.java | 2 +- .../internal/quickpulse/DefaultQuickPulseCoordinator.java | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java index a83bb91f77b..f33b31db680 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java @@ -183,7 +183,7 @@ public Transmission fetchOldestFile() { } try { - TimeUnit.MILLISECONDS.sleep(DELETE_TIMEOUT_ON_FAILURE_IN_MILLS); + Thread.sleep(DELETE_TIMEOUT_ON_FAILURE_IN_MILLS); } catch (InterruptedException e) { break; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/DefaultQuickPulseCoordinator.java b/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/DefaultQuickPulseCoordinator.java index 86003551076..61fd8bce88d 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/DefaultQuickPulseCoordinator.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/quickpulse/DefaultQuickPulseCoordinator.java @@ -21,8 +21,6 @@ package com.microsoft.applicationinsights.internal.quickpulse; -import java.util.concurrent.TimeUnit; - import com.microsoft.applicationinsights.internal.logger.InternalLogger; /** @@ -61,7 +59,7 @@ public void run() { sleepInMS = sendData(); } try { - TimeUnit.MILLISECONDS.sleep(sleepInMS); + Thread.sleep(sleepInMS); } catch (InterruptedException e) { } } From de6f60a499844891bb43d238c988a8b1a6fe9563 Mon Sep 17 00:00:00 2001 From: littleaj <1690572+littleaj@users.noreply.github.com> Date: Fri, 23 Feb 2018 14:12:20 -0800 Subject: [PATCH 8/9] added release note --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8efe08fdbaf..8892fe4d4d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Fixed performance issue on SDK startup. - Fixed PageView telemetry data not being reported. - Fixed Issue #526 (NPE in MapUtil.copy()) +- Fixed Issue #513 (Memory leak in SDKShutdownActivity). This fix upgrades our Servlet version from 2.5 to 3.0. The SDK must now be run on an application server supporting Servlet 3.0. ## Version 2.0.0-BETA - Updating various dependencies to latest version From c581ec2f035c525e7428a5f4c3ccf22edb46e427 Mon Sep 17 00:00:00 2001 From: littleaj <1690572+littleaj@users.noreply.github.com> Date: Fri, 23 Feb 2018 14:13:36 -0800 Subject: [PATCH 9/9] refactored ThreadFactory creation to be a bit more readable. --- .../ActiveTransmissionFileSystemOutput.java | 17 ++--------- .../ActiveTransmissionNetworkOutput.java | 17 ++--------- .../common/TransmissionPolicyManager.java | 15 +++------- .../channel/common/TransmitterImpl.java | 18 ++++-------- .../sampling/AdaptiveTelemetrySampler.java | 13 +-------- .../PerformanceCounterContainer.java | 13 +-------- .../internal/util/ThreadPoolUtils.java | 29 ++++++++++++++++++- 7 files changed, 46 insertions(+), 76 deletions(-) diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionFileSystemOutput.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionFileSystemOutput.java index 4d7f58c6816..25a73953b83 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionFileSystemOutput.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionFileSystemOutput.java @@ -22,7 +22,6 @@ package com.microsoft.applicationinsights.internal.channel.common; import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -39,11 +38,11 @@ * Created by gupele on 12/22/2014. */ public final class ActiveTransmissionFileSystemOutput implements TransmissionOutput { + private static final AtomicInteger INSTANCE_ID_POOL = new AtomicInteger(1); private final ThreadPoolExecutor threadPool; - private final TransmissionOutput actualOutput; - private final TransmissionPolicyStateFetcher transmissionPolicy; + private final int instanceId = INSTANCE_ID_POOL.getAndIncrement(); public ActiveTransmissionFileSystemOutput(TransmissionOutput actualOutput, TransmissionPolicyStateFetcher transmissionPolicy) { Preconditions.checkNotNull(transmissionPolicy, "transmissionPolicy must be a non-null value"); @@ -53,17 +52,7 @@ public ActiveTransmissionFileSystemOutput(TransmissionOutput actualOutput, Trans this.transmissionPolicy = transmissionPolicy; threadPool = ThreadPoolUtils.newLimitedThreadPool(1, 3, 20L, 1024); - final String threadNameFmt = String.format("%s-job-%%d", ActiveTransmissionFileSystemOutput.class.getSimpleName()); - threadPool.setThreadFactory(new ThreadFactory() { - private AtomicInteger threadId = new AtomicInteger(); - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r); - thread.setName(String.format(threadNameFmt, threadId.getAndIncrement())); - thread.setDaemon(true); - return thread; - } - }); + threadPool.setThreadFactory(ThreadPoolUtils.createDaemonThreadFactory(ActiveTransmissionFileSystemOutput.class, instanceId)); } @Override diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionNetworkOutput.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionNetworkOutput.java index 498c6fe8f74..ffd2b342bc7 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionNetworkOutput.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/ActiveTransmissionNetworkOutput.java @@ -22,7 +22,6 @@ package com.microsoft.applicationinsights.internal.channel.common; import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -39,14 +38,13 @@ public final class ActiveTransmissionNetworkOutput implements TransmissionOutput private final static int DEFAULT_MIN_NUMBER_OF_THREADS = 7; private final static int DEFAULT_MAX_NUMBER_OF_THREADS = 7; private final static long DEFAULT_REMOVE_IDLE_THREAD_TIMEOUT_IN_SECONDS = 60L; + private final static AtomicInteger INTSTANCE_ID_POOL = new AtomicInteger(1); private final int maxThreads; - private final ThreadPoolExecutor outputThreads; - private final TransmissionOutput actualOutput; - private final TransmissionPolicyStateFetcher transmissionPolicy; + private final int instanceId = INTSTANCE_ID_POOL.getAndIncrement(); public ActiveTransmissionNetworkOutput(TransmissionOutput actualOutput, TransmissionPolicyStateFetcher transmissionPolicy) { this(actualOutput, transmissionPolicy, DEFAULT_MAX_MESSAGES_IN_BUFFER); @@ -64,16 +62,7 @@ public ActiveTransmissionNetworkOutput(TransmissionOutput actualOutput, Transmis maxThreads, DEFAULT_REMOVE_IDLE_THREAD_TIMEOUT_IN_SECONDS, maxMessagesInBuffer); - final String threadNameFmt = String.format("%s-job-%%d", ActiveTransmissionNetworkOutput.class.getSimpleName()); - outputThreads.setThreadFactory(new ThreadFactory() { - private final AtomicInteger threadId = new AtomicInteger(); - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, String.format(threadNameFmt, threadId.getAndIncrement())); - thread.setDaemon(true); - return thread; - } - }); + outputThreads.setThreadFactory(ThreadPoolUtils.createDaemonThreadFactory(ActiveTransmissionNetworkOutput.class, instanceId)); } @Override diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionPolicyManager.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionPolicyManager.java index d49d1eb3272..ee95f4823a9 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionPolicyManager.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionPolicyManager.java @@ -24,7 +24,6 @@ import java.util.Calendar; import java.util.Date; import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -48,6 +47,7 @@ * Created by gupele on 6/29/2015. */ public final class TransmissionPolicyManager implements Stoppable { + private static final AtomicInteger INSTANCE_ID_POOL = new AtomicInteger(1); // The future date the the transmission is blocked private Date suspensionDate; @@ -62,6 +62,8 @@ public final class TransmissionPolicyManager implements Stoppable { private final TransmissionPolicyState policyState = new TransmissionPolicyState(); private boolean throttlingIsEnabled = true; + private final int instanceId = INSTANCE_ID_POOL.getAndIncrement(); + /** * The class will be activated when a timeout expires */ @@ -150,16 +152,7 @@ private synchronized void createScheduler() { } threads = new ScheduledThreadPoolExecutor(1); - final String threadNameFmt = String.format("%s-job-%%d", TransmissionPolicyManager.class.getSimpleName()); - threads.setThreadFactory(new ThreadFactory() { - private final AtomicInteger threadId = new AtomicInteger(); - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, String.format(threadNameFmt, threadId.getAndIncrement())); - thread.setDaemon(true); - return thread; - } - }); + threads.setThreadFactory(ThreadPoolUtils.createDaemonThreadFactory(TransmissionPolicyManager.class, instanceId)); SDKShutdownActivity.INSTANCE.register(this); } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmitterImpl.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmitterImpl.java index c3723683cd3..41c71a88d01 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmitterImpl.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmitterImpl.java @@ -24,7 +24,6 @@ import java.util.Collection; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.Semaphore; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -113,7 +112,9 @@ public void run() { } } - private final static int MAX_PENDING_SCHEDULE_REQUESTS = 16384; + private static final int MAX_PENDING_SCHEDULE_REQUESTS = 16384; + + private static final AtomicInteger INSTANCE_ID_POOL = new AtomicInteger(1); private final TransmissionDispatcher transmissionDispatcher; @@ -125,6 +126,8 @@ public void run() { private final Semaphore semaphore; + private final int instanceId = INSTANCE_ID_POOL.getAndIncrement(); + public TransmitterImpl(TransmissionDispatcher transmissionDispatcher, TelemetrySerializer serializer, TransmissionsLoader transmissionsLoader) { Preconditions.checkNotNull(transmissionDispatcher, "transmissionDispatcher must be non-null value"); Preconditions.checkNotNull(serializer, "serializer must be non-null value"); @@ -136,16 +139,7 @@ public TransmitterImpl(TransmissionDispatcher transmissionDispatcher, TelemetryS semaphore = new Semaphore(MAX_PENDING_SCHEDULE_REQUESTS); threadPool = new ScheduledThreadPoolExecutor(2); - final String threadNameFmt = String.format("%s-job-%%d", TransmitterImpl.class.getSimpleName()); - threadPool.setThreadFactory(new ThreadFactory() { - private final AtomicInteger threadId = new AtomicInteger(); - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, String.format(threadNameFmt, threadId.getAndIncrement())); - thread.setDaemon(true); - return thread; - } - }); + threadPool.setThreadFactory(ThreadPoolUtils.createDaemonThreadFactory(TransmitterImpl.class, instanceId)); this.transmissionsLoader = transmissionsLoader; this.transmissionsLoader.load(false); diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/sampling/AdaptiveTelemetrySampler.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/sampling/AdaptiveTelemetrySampler.java index 54968953a7e..30e50ec16a9 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/sampling/AdaptiveTelemetrySampler.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/sampling/AdaptiveTelemetrySampler.java @@ -24,9 +24,7 @@ import java.util.Date; import java.util.Set; import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import com.microsoft.applicationinsights.channel.TelemetrySampler; @@ -233,16 +231,7 @@ public boolean isSampledIn(Telemetry telemetry) { private void createTimerThread() { threads = new ScheduledThreadPoolExecutor(1); - final String threadNameFmt = String.format("%s-job-%%d", AdaptiveTelemetrySampler.class.getSimpleName()); - threads.setThreadFactory(new ThreadFactory() { - private final AtomicInteger threadId = new AtomicInteger(); - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, String.format(threadNameFmt, threadId.getAndIncrement())); - thread.setDaemon(true); - return thread; - } - }); + threads.setThreadFactory(ThreadPoolUtils.createDaemonThreadFactory(AdaptiveTelemetrySampler.class)); } private int getIntValueOrDefault(String name, String valueAsString, int defaultValue, int minValue, int maxValue) { diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java b/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java index 71eeccdfc77..6536e6256d2 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java @@ -25,8 +25,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.ThreadFactory; import com.google.common.base.Preconditions; import com.google.common.base.Strings; @@ -260,16 +258,7 @@ public void run() { private void createThreadToCollect() { threads = new ScheduledThreadPoolExecutor(1); - final String threadNameFmt = String.format("%s-job-%%d", PerformanceCounterContainer.class.getSimpleName()); - threads.setThreadFactory(new ThreadFactory() { - private final AtomicInteger threadId = new AtomicInteger(); - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, String.format(threadNameFmt, threadId.getAndIncrement())); - thread.setDaemon(true); - return thread; - } - }); + threads.setThreadFactory(ThreadPoolUtils.createDaemonThreadFactory(PerformanceCounterContainer.class)); } public void setPlugin(PerformanceCountersCollectionPlugin plugin) { diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/util/ThreadPoolUtils.java b/core/src/main/java/com/microsoft/applicationinsights/internal/util/ThreadPoolUtils.java index 2ad0da698c5..ef1c3be02e6 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/util/ThreadPoolUtils.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/util/ThreadPoolUtils.java @@ -22,9 +22,10 @@ package com.microsoft.applicationinsights.internal.util; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; - +import java.util.concurrent.atomic.AtomicInteger; import com.microsoft.applicationinsights.internal.logger.InternalLogger; import org.apache.commons.lang3.exception.ExceptionUtils; @@ -61,4 +62,30 @@ public static void stop(ThreadPoolExecutor threadPool, long timeout, TimeUnit ti Thread.currentThread().interrupt(); } } + + /** + * {@code poolName} will be appended with a hyphen and the threadId. + * @param clazz The class holding the thread pool + * @param instanceId The identifier of the instance of {@code clazz} + */ + public static ThreadFactory createDaemonThreadFactory(final Class clazz, final int instanceId) { + return createNamedDaemonThreadFactory(String.format("%s_%d", clazz.getSimpleName(), instanceId)); + } + + public static ThreadFactory createDaemonThreadFactory(final Class clazz) { + return createNamedDaemonThreadFactory(clazz.getSimpleName()); + } + + public static ThreadFactory createNamedDaemonThreadFactory(final String poolName) { + return new ThreadFactory(){ + private AtomicInteger threadId = new AtomicInteger(); + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r); + thread.setName(String.format("%s-%d", poolName, threadId.getAndIncrement())); + thread.setDaemon(true); + return thread; + } + }; + } }