All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graylog2.plugin.ServerStatus Maven / Gradle / Ivy

There is a newer version: 5.2.7
Show newest version
/**
 * This file is part of Graylog.
 *
 * Graylog is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Graylog is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Graylog.  If not, see .
 */
package org.graylog2.plugin;

import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.inject.Provider;
import org.graylog2.audit.AuditActor;
import org.graylog2.audit.AuditEventSender;
import org.graylog2.plugin.lifecycles.Lifecycle;
import org.graylog2.plugin.system.NodeId;
import org.graylog2.shared.SuppressForbidden;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.graylog2.audit.AuditEventTypes.MESSAGE_PROCESSING_LOCK;

@Singleton
public class ServerStatus {
    private static final Logger LOG = LoggerFactory.getLogger(ServerStatus.class);

    public MessageDetailRecordingStrategy getDetailedMessageRecordingStrategy() {
        return messageDetailRecordingStrategy;
    }

    public enum Capability {
        SERVER,
        MASTER,
        LOCALMODE
    }

    private final EventBus eventBus;
    private final NodeId nodeId;
    private final Provider auditEventSenderProvider;
    private final String clusterId;
    private final DateTime startedAt;
    private final Set capabilitySet;
    private MessageDetailRecordingStrategy messageDetailRecordingStrategy = MessageDetailRecordingStrategy.NEVER;

    private final AtomicBoolean isProcessing = new AtomicBoolean(false);
    private final AtomicBoolean processingPauseLocked = new AtomicBoolean(false);
    private final CountDownLatch runningLatch = new CountDownLatch(1);

    private volatile Lifecycle lifecycle = Lifecycle.UNINITIALIZED;

    @Inject
    public ServerStatus(BaseConfiguration configuration, Set capabilities, EventBus eventBus, Provider auditEventSenderProvider) {
        this.eventBus = eventBus;
        this.nodeId = new NodeId(configuration.getNodeIdFile());
        this.auditEventSenderProvider = auditEventSenderProvider;
        this.clusterId = "";
        this.startedAt = Tools.nowUTC();
        this.capabilitySet = Sets.newHashSet(capabilities); // copy, because we support adding more capabilities later
        this.messageDetailRecordingStrategy = configuration.isMessageRecordingsEnabled()
                ? MessageDetailRecordingStrategy.ALWAYS
                : MessageDetailRecordingStrategy.NEVER;
    }

    public NodeId getNodeId() {
        return nodeId;
    }

    public String getClusterId() {
        return clusterId;
    }

    public Lifecycle getLifecycle() {
        return lifecycle;
    }

    private void publishLifecycle(final Lifecycle lifecycle) {
        setLifecycle(lifecycle);
        eventBus.post(lifecycle);
    }

    private void setLifecycle(final Lifecycle lifecycle) {
        this.lifecycle = lifecycle;
    }

    public void initialize() {
        publishLifecycle(Lifecycle.STARTING);
    }

    public void start() {
        isProcessing.set(true);
        runningLatch.countDown();
        publishLifecycle(Lifecycle.RUNNING);
    }

    public void shutdown(boolean forceProcessing) {
        if (forceProcessing) {
            unlockProcessingPause();
            isProcessing.set(true);
        }

        publishLifecycle(Lifecycle.HALTING);
    }

    public void shutdown() {
        shutdown(true);
    }

    public void fail() {
        isProcessing.set(false);
        publishLifecycle(Lifecycle.FAILED);
    }

    public void throttle() {
        publishLifecycle(Lifecycle.THROTTLED);
    }

    public void running() {
        publishLifecycle(Lifecycle.RUNNING);
    }

    public void overrideLoadBalancerDead() {
        publishLifecycle(Lifecycle.OVERRIDE_LB_DEAD);
    }

    public void overrideLoadBalancerAlive() {
        publishLifecycle(Lifecycle.OVERRIDE_LB_ALIVE);
    }

    public void overrideLoadBalancerThrottled() {
        publishLifecycle(Lifecycle.OVERRIDE_LB_THROTTLED);
    }

    public void awaitRunning(final Runnable runnable) {
        LOG.debug("Waiting for server to enter RUNNING state");
        Uninterruptibles.awaitUninterruptibly(runningLatch);
        LOG.debug("Server entered RUNNING state");

        try {
            LOG.debug("Executing awaitRunning callback");
            runnable.run();
        } catch (Exception e) {
            LOG.error("awaitRunning callback failed", e);
        }
    }

    public DateTime getStartedAt() {
        return startedAt;
    }

    @SuppressForbidden("Deliberate invocation")
    public DateTimeZone getTimezone() {
        return DateTimeZone.getDefault();
    }

    public ServerStatus addCapability(Capability capability) {
        this.capabilitySet.add(capability);
        return this;
    }

    public ServerStatus addCapabilities(Capability... capabilities) {
        this.capabilitySet.addAll(Arrays.asList(capabilities));
        return this;
    }

    public boolean hasCapability(Capability capability) {
        return this.capabilitySet.contains(capability);
    }

    public boolean hasCapabilities(Capability... capabilities) {
        return this.capabilitySet.containsAll(Arrays.asList(capabilities));
    }

    public boolean isProcessing() {
        return isProcessing.get();
    }

    public void pauseMessageProcessing() {
        pauseMessageProcessing(true);
    }

    public void pauseMessageProcessing(boolean locked) {
        // Never override pause lock if already locked.
        if (processingPauseLocked.compareAndSet(false, locked) && locked) {
            auditEventSenderProvider.get().success(AuditActor.system(nodeId), MESSAGE_PROCESSING_LOCK);
        } else if (locked) {
            auditEventSenderProvider.get().failure(AuditActor.system(nodeId), MESSAGE_PROCESSING_LOCK);
        }
        isProcessing.set(false);

        publishLifecycle(Lifecycle.PAUSED);
    }

    public void resumeMessageProcessing() throws ProcessingPauseLockedException {
        if (processingPauseLocked()) {
            throw new ProcessingPauseLockedException("Processing pause is locked. Wait until the locking task has finished " +
                    "or manually unlock if you know what you are doing.");
        }

        start();
    }

    public boolean processingPauseLocked() {
        return processingPauseLocked.get();
    }

    public void unlockProcessingPause() {
        processingPauseLocked.set(false);
    }

    private ServerStatus removeCapability(Capability capability) {
        this.capabilitySet.remove(capability);
        return this;
    }

    public void setLocalMode(boolean localMode) {
        if (localMode) {
            addCapability(Capability.LOCALMODE);
        } else {
            removeCapability(Capability.LOCALMODE);
        }
    }

    public enum MessageDetailRecordingStrategy {
        NEVER,
        ALWAYS;

        public boolean shouldRecord(final Message message) {
            switch (this) {
                case NEVER:
                    return false;
                case ALWAYS:
                    return true;
                default:
                    return false;
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy