/* * Copyright 2016-present Facebook, 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.facebook.buck.event.listener; import com.facebook.buck.counters.CounterRegistry; import com.facebook.buck.counters.IntegerCounter; import com.facebook.buck.counters.SamplingCounter; import com.facebook.buck.event.BuckEventListener; import com.facebook.buck.model.BuildId; import com.facebook.buck.slb.LoadBalancedServiceEvent; import com.facebook.buck.slb.LoadBalancedServiceEventData; import com.facebook.buck.slb.LoadBalancerPingEvent; import com.facebook.buck.slb.LoadBalancerPingEventData; import com.facebook.buck.slb.PerServerData; import com.facebook.buck.slb.PerServerPingData; import com.facebook.buck.slb.ServerHealthManagerEvent; import com.facebook.buck.slb.ServerHealthManagerEventData; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.common.eventbus.Subscribe; import java.net.SocketTimeoutException; import java.net.URI; import java.util.concurrent.ConcurrentMap; public class LoadBalancerEventsListener implements BuckEventListener { public static final String COUNTER_CATEGORY = "buck_slb_counters"; private final CounterRegistry registry; private final ConcurrentMap<URI, ServerCounters> allServerCounters; private final IntegerCounter noHealthyServersCounter; public LoadBalancerEventsListener(CounterRegistry registry) { this.registry = registry; this.allServerCounters = Maps.newConcurrentMap(); noHealthyServersCounter = registry.newIntegerCounter(COUNTER_CATEGORY, "no_healthy_servers_count", ImmutableMap.of()); } @Subscribe public void onLoadBalancerPingEvent(LoadBalancerPingEvent event) { LoadBalancerPingEventData data = event.getData(); for (PerServerPingData perServerData : data.getPerServerData()) { ServerCounters counters = getServerCounters(perServerData.getServer()); counters.getPingRequestCount().inc(); if (perServerData.getException().isPresent()) { Exception exception = perServerData.getException().get(); if (exception instanceof SocketTimeoutException) { counters.getPingRequestTimeoutCount().inc(); } else { counters.getPingRequestErrorCount().inc(); } } if (perServerData.getPingRequestLatencyMillis().isPresent()) { counters .getPingRequestLatencyMillis() .addSample(perServerData.getPingRequestLatencyMillis().get()); } } } @Subscribe public void onServerHealthManagerEvent(ServerHealthManagerEvent event) { ServerHealthManagerEventData data = event.getData(); if (data.noHealthyServersAvailable()) { noHealthyServersCounter.inc(); } for (PerServerData perServerData : data.getPerServerData()) { ServerCounters counters = getServerCounters(perServerData.getServer()); if (perServerData.isServerUnhealthy()) { counters.getServerNotHealthyCount().inc(); } if (perServerData.isBestServer()) { counters.getIsBestServerCount().inc(); } } } @Subscribe public void onLoadBalancedServiceEvent(LoadBalancedServiceEvent event) { LoadBalancedServiceEventData data = event.getData(); ServerCounters counters = getServerCounters(data.getServer()); counters.getRequestCount().inc(); if (data.getRequestSizeBytes().isPresent()) { counters.getRequestSizeBytes().addSample(data.getRequestSizeBytes().get()); } if (data.getResponseSizeBytes().isPresent()) { counters.getResponseSizeBytes().addSample(data.getResponseSizeBytes().get()); } if (data.getException().isPresent()) { Exception exception = data.getException().get(); if (exception instanceof SocketTimeoutException) { counters.getRequestTimeoutCount().inc(); } else { counters.getRequestErrorCount().inc(); } } } private ServerCounters getServerCounters(URI server) { synchronized (allServerCounters) { if (!allServerCounters.containsKey(server)) { allServerCounters.put(server, new ServerCounters(registry, server)); } return Preconditions.checkNotNull(allServerCounters.get(server)); } } @Override public void outputTrace(BuildId buildId) { // Nothing to do. } public static class ServerCounters { public static final String PER_SERVER_CATEGORY = "buck_slb_counters_per_server"; public static final String SERVER_TAG = "server"; private final SamplingCounter pingRequestLatencyMillis; private final IntegerCounter pingRequestCount; private final IntegerCounter pingRequestErrorCount; private final IntegerCounter pingRequestTimeoutCount; private final IntegerCounter serverNotHealthyCount; private final IntegerCounter isBestServerCount; private final SamplingCounter requestSizeBytes; private final SamplingCounter responseSizeBytes; private final IntegerCounter requestCount; private final IntegerCounter requestErrorCount; private final IntegerCounter requestTimeoutCount; public ServerCounters(CounterRegistry registry, URI server) { this.pingRequestLatencyMillis = registry.newSamplingCounter( PER_SERVER_CATEGORY, "ping_request_latency_millis", getTagsForServer(server)); this.pingRequestCount = registry.newIntegerCounter( PER_SERVER_CATEGORY, "ping_request_count", getTagsForServer(server)); this.pingRequestErrorCount = registry.newIntegerCounter( PER_SERVER_CATEGORY, "ping_request_error_count", getTagsForServer(server)); this.pingRequestTimeoutCount = registry.newIntegerCounter( PER_SERVER_CATEGORY, "ping_request_timeout_count", getTagsForServer(server)); this.serverNotHealthyCount = registry.newIntegerCounter( PER_SERVER_CATEGORY, "server_not_healthy_count", getTagsForServer(server)); this.isBestServerCount = registry.newIntegerCounter( PER_SERVER_CATEGORY, "is_best_server_count", getTagsForServer(server)); this.requestSizeBytes = registry.newSamplingCounter( PER_SERVER_CATEGORY, "request_size_bytes", getTagsForServer(server)); this.responseSizeBytes = registry.newSamplingCounter( PER_SERVER_CATEGORY, "response_size_bytes", getTagsForServer(server)); this.requestCount = registry.newIntegerCounter( PER_SERVER_CATEGORY, "request_count", getTagsForServer(server)); this.requestErrorCount = registry.newIntegerCounter( PER_SERVER_CATEGORY, "request_error_count", getTagsForServer(server)); this.requestTimeoutCount = registry.newIntegerCounter( PER_SERVER_CATEGORY, "request_timeout_count", getTagsForServer(server)); } public IntegerCounter getIsBestServerCount() { return isBestServerCount; } public SamplingCounter getPingRequestLatencyMillis() { return pingRequestLatencyMillis; } public IntegerCounter getPingRequestCount() { return pingRequestCount; } public IntegerCounter getPingRequestErrorCount() { return pingRequestErrorCount; } public IntegerCounter getPingRequestTimeoutCount() { return pingRequestTimeoutCount; } public IntegerCounter getServerNotHealthyCount() { return serverNotHealthyCount; } public SamplingCounter getRequestSizeBytes() { return requestSizeBytes; } public SamplingCounter getResponseSizeBytes() { return responseSizeBytes; } public IntegerCounter getRequestCount() { return requestCount; } public IntegerCounter getRequestErrorCount() { return requestErrorCount; } public IntegerCounter getRequestTimeoutCount() { return requestTimeoutCount; } public static ImmutableMap<String, String> getTagsForServer(URI server) { return ImmutableMap.of(SERVER_TAG, server.toString()); } } }