/*
* Copyright 2016 ThoughtWorks, 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.thoughtworks.go.serverhealth;
import com.thoughtworks.go.config.CruiseConfig;
import com.thoughtworks.go.config.CruiseConfigProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class ServerHealthService {
private static final Logger LOG = LoggerFactory.getLogger(ServerHealthService.class);
private HashMap<ServerHealthState, Set<String>> pipelinesWithErrors;
private Map<HealthStateType, ServerHealthState> serverHealth;
public ServerHealthService() {
this.serverHealth = new ConcurrentHashMap<>();
this.pipelinesWithErrors = new HashMap<>();
}
public void removeByScope(HealthStateScope scope) {
for (HealthStateType healthStateType : entryKeys()) {
if (healthStateType.isSameScope(scope)) {
serverHealth.remove(healthStateType);
}
}
}
private Set<HealthStateType> entryKeys() {
return new HashSet<>(serverHealth.keySet());
}
public List<ServerHealthState> filterByScope(HealthStateScope scope) {
List<ServerHealthState> filtered = new ArrayList<>();
for (Map.Entry<HealthStateType, ServerHealthState> entry : sortedEntries()) {
HealthStateType type = entry.getKey();
if (type.isSameScope(scope)) {
filtered.add(entry.getValue());
}
}
return filtered;
}
public HealthStateType update(ServerHealthState serverHealthState) {
HealthStateType type = serverHealthState.getType();
if (serverHealthState.getLogLevel() == HealthStateLevel.OK) {
if (serverHealth.containsKey(type)) {
serverHealth.remove(type);
}
return null;
} else {
serverHealth.put(type, serverHealthState);
return type;
}
}
// called from spring timer
public synchronized void onTimer(CruiseConfigProvider provider) {
CruiseConfig currentConfig = provider.getCurrentConfig();
getAllValidLogs(currentConfig);
LOG.debug("Recomputing material to pipeline mappings.");
HashMap<ServerHealthState, Set<String>> erroredPipelines = new HashMap<>();
for (Map.Entry<HealthStateType, ServerHealthState> entry : serverHealth.entrySet()) {
erroredPipelines.put(entry.getValue(), entry.getValue().getPipelineNames(currentConfig));
}
pipelinesWithErrors = erroredPipelines;
LOG.debug("Done recomputing material to pipeline mappings.");
}
public Set<String> getPipelinesWithErrors(ServerHealthState serverHealthState) {
return pipelinesWithErrors.get(serverHealthState);
}
public ServerHealthStates getAllValidLogs(CruiseConfig cruiseConfig) {
removeMessagesForElementsNoLongerInConfig(cruiseConfig);
removeExpiredMessages();
return logs();
}
public ServerHealthStates getAllLogs() {
return logs();
}
@Deprecated // Remove once we get rid of SpringJUnitTestRunner
public void removeAllLogs() {
serverHealth.clear();
}
private void removeMessagesForElementsNoLongerInConfig(CruiseConfig cruiseConfig) {
for (HealthStateType type : entryKeys()) {
if (type.isRemovedFromConfig(cruiseConfig)) {
this.removeByScope(type);
}
}
}
private void removeExpiredMessages() {
for (Map.Entry<HealthStateType, ServerHealthState> entry : new HashSet<>(serverHealth.entrySet())) {
ServerHealthState value = entry.getValue();
if (value.hasExpired()) {
serverHealth.remove(entry.getKey());
}
}
}
private void removeByScope(HealthStateType type) {
removeByScope(type.getScope());
}
public ServerHealthStates logs() {
ArrayList<ServerHealthState> logs = new ArrayList<>();
for (Map.Entry<HealthStateType, ServerHealthState> entry : sortedEntries()) {
logs.add(entry.getValue());
}
return new ServerHealthStates(logs);
}
private List<Map.Entry<HealthStateType, ServerHealthState>> sortedEntries() {
List<Map.Entry<HealthStateType, ServerHealthState>> entries = new ArrayList<>(serverHealth.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<HealthStateType, ServerHealthState>>() {
public int compare(Map.Entry<HealthStateType, ServerHealthState> one, Map.Entry<HealthStateType, ServerHealthState> other) {
return one.getKey().compareTo(other.getKey());
}
});
return entries;
}
public String getLogsAsText() {
StringBuilder text = new StringBuilder();
for (ServerHealthState state : logs()) {
text.append(state.getDescription());
text.append("\n\t");
text.append(state.getMessage());
text.append("\n");
}
return text.toString();
}
public boolean containsError(HealthStateType type, HealthStateLevel level) {
ServerHealthStates allLogs = getAllLogs();
for (ServerHealthState log : allLogs) {
if (log.getType().equals(type) && log.getLogLevel() == level) {
return true;
}
}
return false;
}
}