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

io.joshworks.snappy.extensions.dashboard.AdminExtension Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 Josue Gontijo
 *
 * 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 io.joshworks.snappy.extensions.dashboard;

import io.joshworks.snappy.ext.ServerData;
import io.joshworks.snappy.ext.SnappyExtension;
import io.joshworks.snappy.extensions.dashboard.log.LogStreamer;
import io.joshworks.snappy.extensions.dashboard.metrics.AppMetricsResource;
import io.joshworks.snappy.extensions.dashboard.resource.ResourceMetricHolder;
import io.joshworks.snappy.extensions.dashboard.resource.ResourcesMetricResource;
import io.joshworks.snappy.extensions.dashboard.resource.RestMetricsHandler;
import io.joshworks.snappy.extensions.dashboard.stats.ServerStats;
import io.joshworks.snappy.handler.HandlerUtil;
import io.joshworks.snappy.handler.MappedEndpoint;
import io.joshworks.snappy.http.ExceptionMapper;
import io.joshworks.snappy.http.MediaType;
import io.joshworks.snappy.http.Response;
import io.joshworks.snappy.property.AppProperties;
import io.undertow.util.Methods;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;

/**
 * Created by Josue on 07/02/2017.
 */
public class AdminExtension implements SnappyExtension {

    private static final Logger logger = LoggerFactory.getLogger(AdminExtension.class);

    private static final String EXTENSION_NAME = "DASHBOARD";
    private static final String PREFIX = "dashboard.";

    private static final String PASSWORD = PREFIX + "password";
    private static final String LOG_LOCATION = PREFIX + "logFile";

    private static final String ADMIN_ROOT_FOLDER = "admin";
    private static final String DEFAULT_PATH = "/";
    private final String path;

    private static final String LOG_SSE = "/logs";

    private static final String METRICS_ENDPOINT = "/metrics";
    private static final String METRICS_STATUS_ENDPOINT = METRICS_ENDPOINT + "/status";
    private static final String METRIC_ENDPOINT = METRICS_ENDPOINT + "/{id}";

    private static final String RESOURCES_METRIC_ENDPOINT = "/resources";
    private static final String RESOURCES_METRIC_STATUS_ENDPOINT = RESOURCES_METRIC_ENDPOINT + "/status";
    private static final String RESOURCE_METRIC_ENDPOINT = RESOURCES_METRIC_ENDPOINT + "/{id}";
    private static final String STATS_ENDPOINT = "/stats";

    public AdminExtension() {
        this(DEFAULT_PATH);
    }

    public AdminExtension(String path) {
        this.path = path;
    }

    private static final ExecutorService executor = Executors.newFixedThreadPool(3);
    public static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    private LogStreamer streamer;

    @Override
    public void onStart(ServerData config) {
        config.adminManager.setAdminPage(path, ADMIN_ROOT_FOLDER, new ArrayList<>());

        registerStatsEndpoint(config);
        registerResourceMetricEndpoints(config);
        registerAppMetricsEndpoint(config);

        String logLocation = AppProperties.get(LOG_LOCATION).orElse(null);
        if (logLocation == null || logLocation.isEmpty()) {
            logger.warn(LOG_LOCATION + " not specified, log won't be available");
        } else {
            streamer = new LogStreamer(executor, logLocation);
        }
        config.adminManager.addEndpoint(HandlerUtil.sse(LOG_SSE, streamer));
    }

    @Override
    public void onShutdown() {
        if (streamer != null) {
            streamer.stopStreaming();
        }
        executor.shutdownNow();
        scheduler.shutdownNow();
    }

    @Override
    public String name() {
        return EXTENSION_NAME;
    }

    private void registerResourceMetricEndpoints(ServerData config) {
        ResourceMetricHolder resourceMetricHolder = wrapHandlerWithMetricsHandler(config);
        final ResourcesMetricResource endpoint = new ResourcesMetricResource(resourceMetricHolder);

        MappedEndpoint getMetrics = HandlerUtil.rest(
                Methods.GET,
                RESOURCES_METRIC_ENDPOINT,
                config.maxMultipartSize,
                endpoint::getMetrics,
                new ExceptionMapper());

        MappedEndpoint getMetric = HandlerUtil.rest(
                Methods.GET,
                RESOURCE_METRIC_ENDPOINT,
                config.maxMultipartSize,
                endpoint::getMetric,
                new ExceptionMapper());


        MappedEndpoint updateMetric = HandlerUtil.rest(
                Methods.PUT,
                RESOURCES_METRIC_STATUS_ENDPOINT,
                config.maxMultipartSize,
                endpoint::updateMetric,
                new ExceptionMapper());


        MappedEndpoint metricStatus = HandlerUtil.rest(
                Methods.GET,
                RESOURCES_METRIC_STATUS_ENDPOINT,
                config.maxMultipartSize,
                endpoint::metricStatus,
                new ExceptionMapper());


        config.adminManager.addEndpoint(getMetrics);
        config.adminManager.addEndpoint(getMetric);
        config.adminManager.addEndpoint(updateMetric);
        config.adminManager.addEndpoint(metricStatus);
    }

    private ResourceMetricHolder wrapHandlerWithMetricsHandler(ServerData config) {
        //Enable metrics only for REST
        Map> splitResources = config.mappedEndpoints.stream()
                .collect(Collectors.partitioningBy(me -> MappedEndpoint.Type.REST.equals(me.type)));

        final ResourceMetricHolder resourceMetricHolder = new ResourceMetricHolder();
        //Replaces the handler reference to a wrapped ResMetricsHandler
        List restResources =
                splitResources.getOrDefault(true, new ArrayList<>())
                        .stream()
                        .map(me -> {
                            RestMetricsHandler restMetricsHandler = new RestMetricsHandler(me.handler);
                            resourceMetricHolder.add(me.method, me.url, restMetricsHandler);
                            return new MappedEndpoint(me.method, me.url, me.type, restMetricsHandler);
                        })
                        .collect(Collectors.toList());

        List replacedResources = new ArrayList<>();
        //don't replace non rest endpoint
        replacedResources.addAll(splitResources.getOrDefault(false, new ArrayList<>())); //non rest resources
        replacedResources.addAll(restResources); //wrapped RestMetricsHandler

        config.mappedEndpoints.clear();
        config.mappedEndpoints.addAll(replacedResources);

        return resourceMetricHolder;
    }

    private void registerStatsEndpoint(ServerData config) {

        MappedEndpoint getMetrics = HandlerUtil.rest(Methods.GET, STATS_ENDPOINT, config.maxMultipartSize, exchange -> {
            return Response.withBody(new ServerStats()).type(MediaType.APPLICATION_JSON_TYPE);
        }, new ExceptionMapper());


        config.adminManager.addEndpoint(getMetrics);
    }

    private void registerAppMetricsEndpoint(ServerData config) {

        AppMetricsResource appMetricsResource = new AppMetricsResource();

        MappedEndpoint getMetrics = HandlerUtil.rest(
                Methods.GET,
                METRICS_ENDPOINT,
                config.maxMultipartSize,
                appMetricsResource::getMetrics,
                new ExceptionMapper());


        MappedEndpoint getMetric = HandlerUtil.rest(
                Methods.GET,
                METRIC_ENDPOINT,
                config.maxMultipartSize,
                appMetricsResource::getMetric,
                new ExceptionMapper());


        MappedEndpoint updateMetrics = HandlerUtil.rest(
                Methods.PUT,
                METRICS_STATUS_ENDPOINT,
                config.maxMultipartSize,
                appMetricsResource::updateMetricState,
                new ExceptionMapper());


        MappedEndpoint metricsStatus = HandlerUtil.rest(
                Methods.GET,
                METRICS_STATUS_ENDPOINT,
                config.maxMultipartSize,
                appMetricsResource::updateMetricState,
                new ExceptionMapper());


        config.adminManager.addEndpoint(getMetrics);
        config.adminManager.addEndpoint(getMetric);
        config.adminManager.addEndpoint(updateMetrics);
        config.adminManager.addEndpoint(metricsStatus);

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy