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

org.swisspush.gateleen.logging.LoggingResourceManager Maven / Gradle / Ivy

package org.swisspush.gateleen.logging;

import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.Message;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.swisspush.gateleen.core.logging.LoggableResource;
import org.swisspush.gateleen.core.logging.RequestLogger;
import org.swisspush.gateleen.core.storage.ResourceStorage;
import org.swisspush.gateleen.core.util.ResourcesUtils;
import org.swisspush.gateleen.core.util.ResponseStatusCodeLogUtil;
import org.swisspush.gateleen.core.util.StatusCode;
import org.swisspush.gateleen.core.util.StringUtils;
import org.swisspush.gateleen.validation.RegexpValidator;
import org.swisspush.gateleen.validation.ValidationException;
import org.swisspush.gateleen.core.validation.ValidationResult;
import org.swisspush.gateleen.validation.Validator;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author https://github.com/mcweba [Marc-Andre Weber]
 */
public class LoggingResourceManager implements LoggableResource {

    static final String UPDATE_ADDRESS = "gateleen.logging-updated";

    private final String loggingUri;
    private final ResourceStorage storage;
    private final Logger log = LoggerFactory.getLogger(LoggingResourceManager.class);
    private final Vertx vertx;
    private LoggingResource loggingResource;
    private final String loggingResourceSchema;
    private boolean logConfigurationResourceChanges = false;

    public LoggingResource getLoggingResource() {
        if (loggingResource == null) {
            loggingResource = new LoggingResource();
        }
        return loggingResource;
    }

    public LoggingResourceManager(Vertx vertx, final ResourceStorage storage, String loggingUri) {
        this.storage = storage;
        this.vertx = vertx;
        this.loggingUri = loggingUri;

        loggingResourceSchema = ResourcesUtils.loadResource("gateleen_logging_schema_logging", true);

        updateLoggingResources();

        // Receive update notifications
        vertx.eventBus().consumer(UPDATE_ADDRESS, (Handler>) event -> updateLoggingResources());
    }

    @Override
    public void enableResourceLogging(boolean resourceLoggingEnabled) {
        this.logConfigurationResourceChanges = resourceLoggingEnabled;
    }

    private void updateLoggingResources() {
        storage.get(loggingUri, buffer -> {
            if (buffer != null) {
                try {
                    updateLoggingResources(buffer);
                } catch (ValidationException e) {
                    log.warn("Could not reconfigure logging resources (filters and headers)", e);
                }
            } else {
                log.warn("Could not get URL '{}'.", (loggingUri == null ? "" : loggingUri));
            }
        });
    }

    private void updateLoggingResources(Buffer buffer) throws ValidationException{
        extractLoggingFilterValues(buffer);

        for (Map payloadFilters : getLoggingResource().getPayloadFilters()) {
            log.info("Applying Logging-Filter: {}", payloadFilters);
        }

        switch (getLoggingResource().getHeaderLogStrategy()) {
        case LOG_ALL:
            log.info("All headers will be logged");
            break;
        case LOG_NONE:
            log.info("No headers will be logged");
            break;
        case LOG_LIST:
            log.info("Headers to log: {}", getLoggingResource().getHeaders().toString());
        }
    }

    public boolean handleLoggingResource(final HttpServerRequest request) {
        if (request.uri().equals(loggingUri) && HttpMethod.PUT == request.method()) {
            request.bodyHandler(loggingResourceBuffer -> {
                try {
                    extractLoggingFilterValues(loggingResourceBuffer);
                } catch (ValidationException validationException) {
                    log.error("Could not parse logging resource: {}", validationException.toString());
                    ResponseStatusCodeLogUtil.info(request, StatusCode.BAD_REQUEST, LoggingResourceManager.class);
                    request.response().setStatusCode(StatusCode.BAD_REQUEST.getStatusCode());
                    request.response().setStatusMessage(StatusCode.BAD_REQUEST.getStatusMessage() + " " + validationException.getMessage());
                    if(validationException.getValidationDetails() != null){
                        request.response().headers().add("content-type", "application/json");
                        request.response().end(validationException.getValidationDetails().encode());
                    } else {
                        request.response().end(validationException.getMessage());
                    }
                    return;
                }
                storage.put(loggingUri, loggingResourceBuffer, status -> {
                    if (status == StatusCode.OK.getStatusCode()) {
                        if(logConfigurationResourceChanges){
                            RequestLogger.logRequest(vertx.eventBus(), request, status, loggingResourceBuffer);
                        }
                        vertx.eventBus().publish(UPDATE_ADDRESS, true);
                    } else {
                        request.response().setStatusCode(status);
                    }
                    ResponseStatusCodeLogUtil.info(request, StatusCode.fromCode(status), LoggingResourceManager.class);
                    request.response().end();
                });
            });
            return true;
        }

        if (request.uri().equals(loggingUri) && HttpMethod.DELETE == request.method()) {
            getLoggingResource().reset();
            log.info("Reset LoggingResource");
        }

        return false;
    }

    private void extractLoggingFilterValues(Buffer loggingResourceBuffer) throws ValidationException {
        ValidationResult validationResult = Validator.validateStatic(loggingResourceBuffer, loggingResourceSchema, log);
        if(!validationResult.isSuccess()){
            throw new ValidationException(validationResult);
        }

        try {
            JsonObject loggingRes = new JsonObject(loggingResourceBuffer.toString("UTF-8"));
            getLoggingResource().reset();

            /* Headers */
            List headersList;
            JsonArray headersJsonArray = loggingRes.getJsonArray("headers");
            if (headersJsonArray == null) {
                getLoggingResource().setHeaderLogStrategy(LoggingResource.HeaderLogStrategy.LOG_ALL);
            } else {
                headersList = headersJsonArray.getList();
                if (headersList != null && headersList.isEmpty()) {
                    getLoggingResource().setHeaderLogStrategy(LoggingResource.HeaderLogStrategy.LOG_NONE);
                } else {
                    getLoggingResource().setHeaderLogStrategy(LoggingResource.HeaderLogStrategy.LOG_LIST);
                }
                getLoggingResource().addHeaders(headersList);
            }

            /* Payload */
            JsonObject payload = loggingRes.getJsonObject("payload");

            JsonArray destinations = payload.getJsonArray("destinations");
            if (destinations != null) {
                Map> destinationEntries = new HashMap<>();

                for (Object destinationObj : destinations) {
                    JsonObject destination = (JsonObject) destinationObj;

                    String name = destination.getString("name");

                    Map options = new HashMap<>();
                    options.put("type", destination.getString("type"));

                    String typeLocation = null;

                    if (destination.getString("type").equalsIgnoreCase("file")) {
                        typeLocation = "file";
                    }
                    else if (destination.getString("type").equalsIgnoreCase("eventBus")) {
                        typeLocation = "address";
                        options.put("metadata", StringUtils.getStringOrEmpty(destination.getString("metadata")));
                        options.put("transmission", StringUtils.getStringOrDefault(destination.getString("transmission"), "publish"));
                    }

                    if (typeLocation != null) {
                        options.put(typeLocation, destination.getString(typeLocation));
                        destinationEntries.put(name, options);
                    }
                    else {
                        log.warn("Could not configure destination '{}'. Missing typeLocation (file|address).", name);
                    }
                }
                getLoggingResource().addFilterDestinations(destinationEntries);
            }

            JsonArray filtersArray = payload.getJsonArray("filters");
            if (filtersArray != null) {
                for (Object filterEntry : filtersArray) {
                    JsonObject filterObject = (JsonObject) filterEntry;
                    Map filterEntries = new HashMap<>();
                    for (String filterName : filterObject.fieldNames()) {
                        final String filterValue = filterObject.getString( filterName );
                        // Ensure value is a valid regular expression (See issue #206).
                        RegexpValidator.throwIfPatternInvalid( filterValue );
                        filterEntries.put(filterName, filterValue );
                    }
                    getLoggingResource().addPayloadFilter(filterEntries);
                }
            }
        } catch (Exception ex) {
            getLoggingResource().reset();
            throw new ValidationException(ex);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy