diff --git a/spectator-nflx-plugin/build.gradle b/spectator-nflx-plugin/build.gradle index dd7ab6bc3..e2e6e20c9 100644 --- a/spectator-nflx-plugin/build.gradle +++ b/spectator-nflx-plugin/build.gradle @@ -4,11 +4,7 @@ dependencies { compile project(':spectator-ext-jvm') compile project(':spectator-ext-sandbox') compile project(':spectator-reg-servo') - compile "com.fasterxml.jackson.core:jackson-databind:$version_jackson" compile "com.google.inject:guice:$version_guice" compile "com.netflix.archaius:archaius-core:$version_archaius1" - compile "com.netflix.eureka:eureka-client:$version_eureka" - compile "com.netflix.iep-shadow:iepshadow-iep-module-rxnetty:$version_iep" - compile "com.netflix.iep-shadow:iepshadow-iep-rxhttp:$version_iep" testCompile "com.netflix.governator:governator:$version_governator" } diff --git a/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/ChronosGcEventListener.java b/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/ChronosGcEventListener.java deleted file mode 100644 index 10a0a5f56..000000000 --- a/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/ChronosGcEventListener.java +++ /dev/null @@ -1,186 +0,0 @@ -/** - * Copyright 2015 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.netflix.spectator.nflx; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.netflix.config.DynamicBooleanProperty; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicStringProperty; -import com.netflix.spectator.api.Registry; -import iep.com.netflix.iep.http.RxHttp; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.gc.GcEvent; -import com.netflix.spectator.gc.GcEventListener; -import com.sun.management.GcInfo; -import io.netty.buffer.ByteBuf; -import iep.io.reactivex.netty.protocol.http.client.HttpClientResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import rx.functions.Action0; -import rx.functions.Action1; - -import javax.inject.Inject; -import java.io.IOException; -import java.net.URI; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Listener that sends GC events to a chronos backend. - */ -class ChronosGcEventListener implements GcEventListener { - - private static final DynamicBooleanProperty ENABLED = - DynamicPropertyFactory.getInstance().getBooleanProperty("spectator.gc.chronosEnabled", true); - - private static final DynamicStringProperty CHRONOS_URI = - DynamicPropertyFactory.getInstance().getStringProperty( - "spectator.gc.chronosUri", "niws://chronos_gc/api/v2/event"); - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final Registry registry; - private final Id requestCount; - - private final ObjectMapper mapper = new ObjectMapper(); - - // Keep track of the previous end time to provide additional context for chronos visualization - // without needing to find the previous event. Stored as atomic long as there is no guarantee - // that the listener won't receive events from multiple threads. - private final AtomicLong previousEndTime = new AtomicLong(-1L); - - private final RxHttp rxHttp; - - /** Create a new instance. */ - @Inject - ChronosGcEventListener(RxHttp rxHttp, Registry registry) { - this.rxHttp = rxHttp; - this.registry = registry; - requestCount = registry.createId("spectator.gc.chronosPost"); - } - - private String getenv(String k) { - String v = System.getenv(k); - return (v == null || v.length() == 0) ? "unknown" : v; - } - - /** Convert a GC event into a map. */ - Map toGcInfoMap(GcEvent event) { - final GcInfo info = event.getInfo().getGcInfo(); - Map map = new HashMap<>(); - map.put("id", info.getId()); - map.put("startTime", event.getStartTime()); - map.put("endTime", event.getStartTime() + info.getDuration()); - map.put("previousEndTime", previousEndTime.get()); - map.put("duration", info.getDuration()); - map.put("memoryBeforeGc", info.getMemoryUsageBeforeGc()); - map.put("memoryAfterGc", info.getMemoryUsageAfterGc()); - return map; - } - - /** Convert a GC event into a map. */ - Map toEventMap(GcEvent event) { - Map map = new HashMap<>(); - map.put("action", event.getInfo().getGcAction()); - map.put("cause", event.getInfo().getGcCause()); - map.put("name", event.getName()); - map.put("gcInfo", toGcInfoMap(event)); - map.put("app", getenv("NETFLIX_APP")); - map.put("cluster", getenv("NETFLIX_CLUSTER")); - map.put("asg", getenv("NETFLIX_AUTO_SCALE_GROUP")); - map.put("region", getenv("EC2_REGION")); - map.put("zone", getenv("EC2_AVAILABILITY_ZONE")); - map.put("ami", getenv("EC2_AMI_ID")); - map.put("node", getenv("EC2_INSTANCE_ID")); - return map; - } - - private void sendToChronos(final byte[] json, final boolean blocking) { - final URI uri = URI.create(CHRONOS_URI.get()); - - final CountDownLatch latch = new CountDownLatch(1); - final long start = System.nanoTime(); - rxHttp.postJson(uri, json).subscribe( - new Action1>() { - @Override - public void call(HttpClientResponse response) { - final int code = response.getStatus().code(); - if (code != 200) { - logger.warn("failed to send GC event to chronos (status={})", code); - } - final long latency = System.nanoTime() - start; - final Id timerId = requestCount.withTag("status", "" + code); - registry.timer(timerId).record(latency, TimeUnit.NANOSECONDS); - } - }, - new Action1() { - @Override - public void call(Throwable t) { - logger.warn("failed to send GC event to chronos", t); - final String status = t.getClass().getSimpleName(); - final long latency = System.nanoTime() - start; - final Id timerId = requestCount.withTag("status", status); - registry.timer(timerId).record(latency, TimeUnit.NANOSECONDS); - latch.countDown(); - } - }, - new Action0() { - @Override - public void call() { - latch.countDown(); - } - } - ); - - // Used for unit tests so we can reliably detect completion - if (blocking) { - try { - latch.await(); - } catch (InterruptedException e) { - // Ignore - } - } - } - - /** - * Send GC event to chronos. - */ - void onComplete(final GcEvent event, boolean blocking) { - if (!ENABLED.get()) { - return; - } - - try { - final byte[] json = mapper.writeValueAsBytes(toEventMap(event)); - sendToChronos(json, blocking); - } catch (IOException e) { - logger.warn("failed to send GC event to chronos", e); - } - - previousEndTime.set(event.getStartTime() + event.getInfo().getGcInfo().getDuration()); - } - - @Override public void onComplete(final GcEvent event) { - onComplete(event, false); - } - - /** Shutdown the client used to send data to chronos. */ - public void shutdown() { - } -} diff --git a/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/Plugin.java b/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/Plugin.java index c7eb4d5e3..c88e73673 100644 --- a/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/Plugin.java +++ b/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/Plugin.java @@ -43,14 +43,14 @@ final class Plugin { /** Create a new instance. */ @Inject - Plugin(Registry registry, ChronosGcEventListener listener) throws IOException { + Plugin(Registry registry) throws IOException { AbstractConfiguration config = ConfigurationManager.getConfigInstance(); final boolean enabled = config.getBoolean(ENABLED_PROP, true); if (enabled) { ConfigurationManager.loadPropertiesFromResources(CONFIG_FILE); if (config.getBoolean("spectator.gc.loggingEnabled")) { - GC_LOGGER.start(listener); + GC_LOGGER.start(null); LOGGER.info("gc logging started"); } else { LOGGER.info("gc logging is not enabled"); diff --git a/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/SpectatorModule.java b/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/SpectatorModule.java index adccf4f8c..372ced4bd 100644 --- a/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/SpectatorModule.java +++ b/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/SpectatorModule.java @@ -16,7 +16,6 @@ package com.netflix.spectator.nflx; import com.netflix.spectator.servo.ServoRegistry; -import iep.com.netflix.iep.rxnetty.RxNettyModule; import javax.annotation.PreDestroy; import javax.inject.Inject; @@ -63,7 +62,6 @@ */ public final class SpectatorModule extends AbstractModule { @Override protected void configure() { - install(new RxNettyModule()); bind(Plugin.class).asEagerSingleton(); bind(StaticManager.class).asEagerSingleton(); } diff --git a/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/TestModule.java b/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/TestModule.java index 821f84795..2e023e0af 100644 --- a/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/TestModule.java +++ b/spectator-nflx-plugin/src/main/java/com/netflix/spectator/nflx/TestModule.java @@ -16,8 +16,6 @@ package com.netflix.spectator.nflx; import com.google.inject.AbstractModule; -import iep.com.netflix.iep.http.BasicServerRegistry; -import iep.com.netflix.iep.http.ServerRegistry; import com.netflix.spectator.api.DefaultRegistry; import com.netflix.spectator.api.ExtendedRegistry; import com.netflix.spectator.api.Registry; @@ -35,8 +33,5 @@ public final class TestModule extends AbstractModule { final Registry registry = new DefaultRegistry(); bind(ExtendedRegistry.class).toInstance(new ExtendedRegistry(registry)); bind(Registry.class).toInstance(registry); - - // Allows auto-plugin to come up without needing to get DiscoveryClient to work - bind(ServerRegistry.class).toInstance(new BasicServerRegistry()); } } diff --git a/spectator-nflx-plugin/src/main/resources/spectator.properties b/spectator-nflx-plugin/src/main/resources/spectator.properties index c591788a6..4a8a169d3 100644 --- a/spectator-nflx-plugin/src/main/resources/spectator.properties +++ b/spectator-nflx-plugin/src/main/resources/spectator.properties @@ -17,14 +17,3 @@ # Should we enable gc logging? Only checked at startup. spectator.gc.loggingEnabled=true - -# Should we send gc events to chronos backend? Logging must be enabled. This property is only -# checked at startup. -spectator.gc.chronosEnabled=true - -# Rest client for chronos gc backend -chronos_gc.niws.client.ReadTimeout=15000 -chronos_gc.niws.client.ConnectTimeout=5000 -chronos_gc.niws.client.MaxAutoRetriesNextServer=2 -chronos_gc.niws.client.GzipEnabled=false -chronos_gc.niws.client.DeploymentContextBasedVipAddresses=chronos_backend-gc:7001 diff --git a/spectator-nflx-plugin/src/test/java/com/netflix/spectator/nflx/ChronosGcEventListenerTest.java b/spectator-nflx-plugin/src/test/java/com/netflix/spectator/nflx/ChronosGcEventListenerTest.java deleted file mode 100644 index 546227b2f..000000000 --- a/spectator-nflx-plugin/src/test/java/com/netflix/spectator/nflx/ChronosGcEventListenerTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Copyright 2015 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.netflix.spectator.nflx; - -import com.netflix.config.ConfigurationManager; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.Registry; -import iep.com.netflix.iep.http.RxHttp; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Spectator; -import com.netflix.spectator.gc.GcEvent; -import com.sun.management.GarbageCollectionNotificationInfo; -import com.sun.management.GarbageCollectorMXBean; -import com.sun.management.GcInfo; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.net.InetSocketAddress; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicIntegerArray; - -@RunWith(JUnit4.class) -public class ChronosGcEventListenerTest { - - private static final String client = "chronos_gc"; - private static final int retries = 5; - - private static HttpServer server; - private static int port; - - private static Registry registry = new DefaultRegistry(); - - private static AtomicInteger statusCode = new AtomicInteger(200); - private static AtomicIntegerArray statusCounts = new AtomicIntegerArray(600); - - private static void set(String k, String v) { - ConfigurationManager.getConfigInstance().setProperty(k, v); - } - - @BeforeClass - public static void startServer() throws Exception { - server = HttpServer.create(new InetSocketAddress(0), 100); - server.setExecutor(Executors.newFixedThreadPool(10, new ThreadFactory() { - @Override public Thread newThread(Runnable r) { - return new Thread(r, "HttpServer"); - } - })); - port = server.getAddress().getPort(); - - server.createContext("/api/v2/event", new HttpHandler() { - @Override - public void handle(HttpExchange exchange) throws IOException { - statusCounts.incrementAndGet(statusCode.get()); - exchange.sendResponseHeaders(statusCode.get(), -1L); - exchange.close(); - } - }); - - server.start(); - - String uri = "niws://chronos_gc/http://localhost:" + port + "/api/v2/event"; - set("spectator.gc.chronosUri", uri); - set(client + ".niws.client.MaxAutoRetriesNextServer", "" + retries); - set(client + ".niws.client.RetryDelay", "10"); - } - - @AfterClass - public static void stopServer() { - server.stop(0); - } - - private ChronosGcEventListener newListener() { - return new ChronosGcEventListener(new RxHttp(null), registry); - } - - private long reqCount(int status) { - Id requests = registry.createId("spectator.gc.chronosPost", "status", "" + status); - return registry.timer(requests).count(); - } - - private GcEvent newGcEvent() { - GcInfo gcInfo = null; - for (java.lang.management.GarbageCollectorMXBean mbean : ManagementFactory.getGarbageCollectorMXBeans()) { - GarbageCollectorMXBean sunMbean = (GarbageCollectorMXBean) mbean; - while (sunMbean.getLastGcInfo() == null) { - System.gc(); - } - gcInfo = sunMbean.getLastGcInfo(); - } - final GarbageCollectionNotificationInfo info = new GarbageCollectionNotificationInfo( - "test", "action", "cause", gcInfo); - return new GcEvent(info, 1234567890L); - } - - @Test - public void ok() throws Exception { - statusCode.set(200); - long before = reqCount(200); - - final ChronosGcEventListener listener = newListener(); - listener.onComplete(newGcEvent(), true); - listener.shutdown(); - - Assert.assertTrue(reqCount(200) > before); - } -} - diff --git a/spectator-nflx/src/main/resources/spectator.properties b/spectator-nflx/src/main/resources/spectator.properties index 8d9a96e5c..4a8a169d3 100644 --- a/spectator-nflx/src/main/resources/spectator.properties +++ b/spectator-nflx/src/main/resources/spectator.properties @@ -17,16 +17,3 @@ # Should we enable gc logging? Only checked at startup. spectator.gc.loggingEnabled=true - -# Should we send gc events to chronos backend? Logging must be enabled. This property is only -# checked at startup. -spectator.gc.chronosEnabled=true - -# Rest client for chronos gc backend -chronos_gc.niws.client.ReadTimeout=15000 -chronos_gc.niws.client.ConnectTimeout=5000 -chronos_gc.niws.client.MaxAutoRetries=0 -chronos_gc.niws.client.MaxAutoRetriesNextServer=2 -chronos_gc.niws.client.OkToRetryOnAllOperations=true -chronos_gc.niws.client.DeploymentContextBasedVipAddresses=chronos_backend-gc:7001 -chronos_gc.niws.client.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList diff --git a/spectator-nflx/src/test/resources/eureka-client.properties b/spectator-nflx/src/test/resources/eureka-client.properties deleted file mode 100644 index e9d72a8c2..000000000 --- a/spectator-nflx/src/test/resources/eureka-client.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright 2015 Netflix, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -eureka.validateInstanceId=false -eureka.datacenter=default -eureka.shouldUseDns=false -eureka.shouldFetchRegistry=false -eureka.serviceUrl.default=http://localhost/eureka/v2/ \ No newline at end of file