Skip to content

Commit

Permalink
Add stats for DiscoveryClient (#1282)
Browse files Browse the repository at this point in the history
Introduce a nested class for `DiscoveryClient` to make it easier for
users to read helpful attributes that can assist in log analysis and
debugging. Most of these attributes are captured by existing metrics:

- `initTimestampMs`: timestamp when the client was initialized
- `localRegistrySize`: number of instances for all applications
- `lastSuccessfulRegistryFetchTimestampMs`: timestamp for last successful fetch
- `lastSuccessfulHeartbeatTimestampMs`: timestamp for last successful heartbeat

Add a new attribute called `initLocalRegistrySize`, which is the
number of instances for all applications read when the client was
initialized. Include a helper method that uses this attribute so
that users can determine whether the client's initial fetch of registry
information succeeded or failed. Note that other accessors are suffixed
with `Ms` (for milliseconds) to denote the time unit.

Additionally, update the existing `registrySize` with the value from
`initLocalRegistrySize` during initialization instead of waiting until
the first local registry refresh.

Co-authored-by: John Bennett <bennett@netflix.com>
  • Loading branch information
yobennett and John Bennett committed Apr 7, 2020
1 parent f139fc3 commit cac06f4
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ public class DiscoveryClient implements EurekaClient {
protected final EurekaTransportConfig transportConfig;

private final long initTimestampMs;
private final int initRegistrySize;

private final Stats stats = new Stats();

private static final class EurekaTransport {
private ClosableResolver bootstrapResolver;
Expand Down Expand Up @@ -381,8 +384,10 @@ public synchronized BackupRegistry get() {
DiscoveryManager.getInstance().setEurekaClientConfig(config);

initTimestampMs = System.currentTimeMillis();
initRegistrySize = this.getApplications().size();
registrySize = initRegistrySize;
logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}",
initTimestampMs, this.getApplications().size());
initTimestampMs, initRegistrySize);

return; // no need to setup up an network tasks and we are done
}
Expand Down Expand Up @@ -465,8 +470,10 @@ public synchronized BackupRegistry get() {
DiscoveryManager.getInstance().setEurekaClientConfig(config);

initTimestampMs = System.currentTimeMillis();
initRegistrySize = this.getApplications().size();
registrySize = initRegistrySize;
logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}",
initTimestampMs, this.getApplications().size());
initTimestampMs, initRegistrySize);
}

private void scheduleServerEndpointTask(EurekaTransport eurekaTransport,
Expand Down Expand Up @@ -1743,4 +1750,53 @@ private long computeStalenessMonitorDelay(long delay) {
}
}

/**
* Gets stats for the DiscoveryClient.
*
* @return The DiscoveryClientStats instance.
*/
public Stats getStats() {
return stats;
}

/**
* Stats is used to track useful attributes of the DiscoveryClient. It includes helpers that can aid
* debugging and log analysis.
*/
public class Stats {

private Stats() {}

public int initLocalRegistrySize() {
return initRegistrySize;
}

public long initTimestampMs() {
return initTimestampMs;
}

public int localRegistrySize() {
return registrySize;
}

public long lastSuccessfulRegistryFetchTimestampMs() {
return lastSuccessfulRegistryFetchTimestamp;
}

public long lastSuccessfulHeartbeatTimestampMs() {
return lastSuccessfulHeartbeatTimestamp;
}

/**
* Used to determine if the Discovery client's first attempt to fetch from the service registry succeeded with
* non-empty results.
*
* @return true if succeeded, failed otherwise
*/
public boolean initSucceeded() {
return initLocalRegistrySize() > 0 && initTimestampMs() > 0;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.netflix.discovery;

import com.netflix.discovery.junit.resource.DiscoveryClientResource;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
* Tests for DiscoveryClient stats reported when initial registry fetch fails.
*/
public class DiscoveryClientStatsInitFailedTest extends BaseDiscoveryClientTester {

@Before
public void setUp() throws Exception {
setupProperties();
populateRemoteRegistryAtStartup();
setupDiscoveryClient();
}

@After
public void tearDown() throws Exception {
shutdownDiscoveryClient();
DiscoveryClientResource.clearDiscoveryClientConfig();
}

@Test
public void testEmptyInitLocalRegistrySize() throws Exception {
Assert.assertTrue(client instanceof DiscoveryClient);
DiscoveryClient clientImpl = (DiscoveryClient) client;
Assert.assertEquals(0, clientImpl.getStats().initLocalRegistrySize());
}

@Test
public void testInitFailed() throws Exception {
Assert.assertTrue(client instanceof DiscoveryClient);
DiscoveryClient clientImpl = (DiscoveryClient) client;
Assert.assertFalse(clientImpl.getStats().initSucceeded());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.netflix.discovery;

import org.junit.Assert;
import org.junit.Test;

/**
* Tests for DiscoveryClient stats reported when initial registry fetch succeeds.
*/
public class DiscoveryClientStatsTest extends AbstractDiscoveryClientTester {

@Test
public void testNonEmptyInitLocalRegistrySize() throws Exception {
Assert.assertTrue(client instanceof DiscoveryClient);
DiscoveryClient clientImpl = (DiscoveryClient) client;
Assert.assertEquals(createLocalApps().size(), clientImpl.getStats().initLocalRegistrySize());
}

@Test
public void testInitSucceeded() throws Exception {
Assert.assertTrue(client instanceof DiscoveryClient);
DiscoveryClient clientImpl = (DiscoveryClient) client;
Assert.assertTrue(clientImpl.getStats().initSucceeded());
}

}

0 comments on commit cac06f4

Please sign in to comment.