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

com.opsmatters.newrelic.batch.parsers.DashboardParser Maven / Gradle / Ivy

/*
 * Copyright 2018 Gerald Curley
 *
 * 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.opsmatters.newrelic.batch.parsers;

import java.io.Reader;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.logging.Logger;
import org.yaml.snakeyaml.Yaml;
import com.opsmatters.newrelic.api.model.insights.Dashboard;
import com.opsmatters.newrelic.api.model.insights.Metadata;
import com.opsmatters.newrelic.api.model.insights.Filter;
import com.opsmatters.newrelic.api.model.insights.widgets.Widget;
import com.opsmatters.newrelic.api.model.insights.widgets.EventChart;
import com.opsmatters.newrelic.api.model.insights.widgets.BreakdownMetricChart;
import com.opsmatters.newrelic.api.model.insights.widgets.FacetChart;
import com.opsmatters.newrelic.api.model.insights.widgets.InventoryChart;
import com.opsmatters.newrelic.api.model.insights.widgets.Markdown;
import com.opsmatters.newrelic.api.model.insights.widgets.MetricLineChart;
import com.opsmatters.newrelic.api.model.insights.widgets.ThresholdEventChart;
import com.opsmatters.newrelic.api.model.insights.widgets.TrafficLightChart;
import com.opsmatters.newrelic.api.model.insights.widgets.MarkdownData;
import com.opsmatters.newrelic.api.model.insights.widgets.EventsData;
import com.opsmatters.newrelic.api.model.insights.widgets.MetricsData;
import com.opsmatters.newrelic.api.model.insights.widgets.InventoryData;
import com.opsmatters.newrelic.api.model.insights.widgets.Threshold;
import com.opsmatters.newrelic.api.model.insights.widgets.TrafficLight;
import com.opsmatters.newrelic.api.model.insights.widgets.TrafficLightState;
import com.opsmatters.newrelic.api.model.insights.widgets.Presentation;
import com.opsmatters.newrelic.api.model.insights.widgets.DrilldownPresentation;
import com.opsmatters.newrelic.api.model.insights.widgets.ThresholdPresentation;
import com.opsmatters.newrelic.api.model.insights.widgets.TrafficLightPresentation;
import com.opsmatters.newrelic.api.model.insights.widgets.Layout;
import com.opsmatters.newrelic.api.model.metrics.Metric;

/**
 * Parser that converts dashboards from YAML format.
 * 
 * @author Gerald Curley (opsmatters)
 */
public class DashboardParser extends BaseParser
{
    private static final Logger logger = Logger.getLogger(DashboardParser.class.getName());

    /**
     * Private constructor.
     */
    private DashboardParser()
    {
    }

    /**
     * Reads the dashboards from the given string.
     * @param contents The contents of the file as a YAML string
     * @return The dashboards read from the YAML string
     */
    public static List parseYaml(String contents)
    {
        return new DashboardParser().getDashboards(new Yaml().load(contents));
    }

    /**
     * Reads the dashboards from the given reader.
     * @param reader The reader used to read the YAML string
     * @return The dashboards read from the YAML string
     */
    public static List parseYaml(Reader reader)
    {
        return new DashboardParser().getDashboards(new Yaml().load(reader));
    }

    /**
     * Reads the dashboards from the given object.
     * @param o The dashboards as a map
     * @return The dashboards read from the map
     */
    private List getDashboards(Object o)
    {
        List ret = new ArrayList();

        if(o instanceof Map)
        {
            Map map = (Map)o;
            for(Map.Entry entry : map.entrySet())
            {
                if(entry.getValue() instanceof Map)
                    ret.add(getDashboard(entry.getKey(), (Map)entry.getValue()));
                else
                    logger.severe("Not a YAML document");
            }
        }
        else
        {
            logger.severe("Not a YAML document");
        }

        return ret;
    }

    /**
     * Creates a dashboard from the given map.
     * @param title The title of the dashboard
     * @param map The configuration properties
     * @return The dashboard
     */
    private Dashboard getDashboard(String title, Map map)
    {
        // Get the filter
        List eventTypes = null;
        List attributes = null;
        Map filter = getAs(map,  Dashboard.FILTER, Map.class);
        if(filter != null)
        {
            eventTypes = getAs(filter, Filter.EVENT_TYPES, List.class);
            attributes = getAs(filter, Filter.ATTRIBUTES, List.class);
        }

        return Dashboard.builder()
            .title(title)
            .icon(getAs(map, Dashboard.ICON, String.class, false))
            .version(getAs(map, Metadata.VERSION, Integer.class))
            .visibility(getAs(map, Dashboard.VISIBILITY, String.class))
            .editable(getAs(map, Dashboard.EDITABLE, String.class))
            .setFilter(eventTypes, attributes)
            .widgets(getWidgets(getAs(map, Dashboard.WIDGETS, Map.class)))
            .build();
    }

    /**
     * Reads a list of widgets from the given map.
     * @param map The map to read the widgets from
     * @return The widgets
     */
    private List getWidgets(Map map)
    {
        List ret = new ArrayList();

        if(map != null)
        {
            for(Map.Entry entry : map.entrySet())
            {
                if(entry.getValue() instanceof Map)
                    ret.add(getWidget(entry.getKey(), (Map)entry.getValue()));
                else
                    logger.severe("Not a widget document");
            }
        }

        return ret;
    }

    /**
     * Creates a widget from the given map.
     * @param title The title of the widget
     * @param map The configuration properties
     * @return The widget
     */
    private Widget getWidget(String title, Map map)
    {
        Widget ret = null;
        String visualization = getAs(map, Widget.VISUALIZATION, String.class);
        if(visualization != null)
        {
            if(EventChart.Visualization.contains(visualization))
                ret = getEventChart(visualization, title, map);
            else if(BreakdownMetricChart.Visualization.contains(visualization))
                ret = getBreakdownMetricChart(visualization, title, map);
            else if(FacetChart.Visualization.contains(visualization))
                ret = getFacetChart(visualization, title, map);
            else if(InventoryChart.Visualization.contains(visualization))
                ret = getInventoryChart(visualization, title, map);
            else if(Markdown.Visualization.contains(visualization))
                ret = getMarkdown(visualization, title, map);
            else if(MetricLineChart.Visualization.contains(visualization))
                ret = getMetricLineChart(visualization, title, map);
            else if(ThresholdEventChart.Visualization.contains(visualization))
                ret = getThresholdEventChart(visualization, title, map);
            else if(TrafficLightChart.Visualization.contains(visualization))
                ret = getTrafficLightChart(visualization, title, map);
        }

        return ret;
    }

    /**
     * Creates a markdown widget.
     * @param visualization The visualization type of the widget
     * @param title The title of the widget
     * @param map The configuration properties
     * @return The widget
     */
    private Widget getMarkdown(String visualization, String title, Map map)
    {
        Markdown.Builder builder = Markdown.builder()
            .visualization(visualization)
            .addData(getMarkdownData(getAs(map, Widget.DATA, Map.class)));
        return getWidget(builder, title, map).build();
    }

    /**
     * Creates an event chart widget.
     * @param visualization The visualization type of the widget
     * @param title The title of the widget
     * @param map The configuration properties
     * @return The widget
     */
    private Widget getEventChart(String visualization, String title, Map map)
    {
        EventChart.Builder builder = EventChart.builder()
            .visualization(visualization)
            .addData(getEventsData(getAs(map, Widget.DATA, Map.class)));
        return getWidget(builder, title, map).build();
    }

    /**
     * Creates a facet chart widget.
     * @param visualization The visualization type of the widget
     * @param title The title of the widget
     * @param map The configuration properties
     * @return The widget
     */
    private Widget getFacetChart(String visualization, String title, Map map)
    {
        FacetChart.Builder builder = FacetChart.builder()
            .visualization(visualization)
            .addData(getEventsData(getAs(map, Widget.DATA, Map.class)));

        Integer id = getAs(map, DrilldownPresentation.DRILLDOWN_DASHBOARD_ID, Integer.class, false);
        if(id != null)
            builder = builder.drilldownDashboardId(id);

        return getWidget(builder, title, map).build();
    }

    /**
     * Creates a threshold event chart widget.
     * @param visualization The visualization type of the widget
     * @param title The title of the widget
     * @param map The configuration properties
     * @return The widget
     */
    private Widget getThresholdEventChart(String visualization, String title, Map map)
    {
        ThresholdEventChart.Builder builder = ThresholdEventChart.builder()
            .visualization(visualization)
            .threshold(getThreshold(getAs(map, ThresholdPresentation.THRESHOLD, Map.class)))
            .addData(getEventsData(getAs(map, Widget.DATA, Map.class)));
        return getWidget(builder, title, map).build();
    }

    /**
     * Creates a breakdown metric chart widget.
     * @param visualization The visualization type of the widget
     * @param title The title of the widget
     * @param map The configuration properties
     * @return The widget
     */
    private Widget getBreakdownMetricChart(String visualization, String title, Map map)
    {
        BreakdownMetricChart.Builder builder = BreakdownMetricChart.builder()
            .visualization(visualization)
            .addData(getMetricsData(getAs(map, Widget.DATA, Map.class)));
        return getWidget(builder, title, map).build();
    }

    /**
     * Creates a metric line chart widget.
     * @param visualization The visualization type of the widget
     * @param title The title of the widget
     * @param map The configuration properties
     * @return The widget
     */
    private Widget getMetricLineChart(String visualization, String title, Map map)
    {
        MetricLineChart.Builder builder = MetricLineChart.builder()
            .visualization(visualization)
            .addData(getMetricsData(getAs(map, Widget.DATA, Map.class)));
        return getWidget(builder, title, map).build();
    }

    /**
     * Creates an inventory chart widget.
     * @param visualization The visualization type of the widget
     * @param title The title of the widget
     * @param map The configuration properties
     * @return The widget
     */
    private Widget getInventoryChart(String visualization, String title, Map map)
    {
        InventoryChart.Builder builder = InventoryChart.builder()
            .visualization(visualization)
            .addData(getInventoryData(getAs(map, Widget.DATA, Map.class)));
        return getWidget(builder, title, map).build();
    }

    /**
     * Creates a traffic light chart widget.
     * @param visualization The visualization type of the widget
     * @param title The title of the widget
     * @param map The configuration properties
     * @return The widget
     */
    private Widget getTrafficLightChart(String visualization, String title, Map map)
    {
        TrafficLightChart.Builder builder = TrafficLightChart.builder()
            .visualization(visualization)
            .addData(getEventsData(getAs(map, Widget.DATA, Map.class)))
            .addTrafficLight(getTrafficLight(getAs(map, TrafficLightPresentation.TRAFFIC_LIGHT, Map.class)));
        return getWidget(builder, title, map).build();
    }

    /**
     * Creates a markdown data item.
     * @param map The configuration properties
     * @return The widget data
     */
    private MarkdownData getMarkdownData(Map map)
    {
        return MarkdownData.builder()
            .source(getAs(map, MarkdownData.SOURCE, String.class))
            .build();
    }

    /**
     * Creates an event data item.
     * @param map The configuration properties
     * @return The widget data
     */
    private EventsData getEventsData(Map map)
    {
        return EventsData.builder()
            .nrql(getAs(map, EventsData.NRQL, String.class))
            .build();
    }

    /**
     * Creates a metric data item.
     * @param map The configuration properties
     * @return The widget data
     */
    private MetricsData getMetricsData(Map map)
    {
        MetricsData.Builder builder = MetricsData.builder()
            .orderBy(getAs(map, MetricsData.ORDER_BY, String.class, false));

        Integer duration = getAs(map, MetricsData.DURATION, Integer.class, false);
        if(duration != null)
            builder = builder.duration(duration);

        List metrics = null;
        List list = getAs(map, MetricsData.METRICS, List.class, false);
        if(list != null)
        {
            metrics = new ArrayList();
            for(Object item : list)
                metrics.add(getMetric(coerceTo(MetricsData.METRICS, item, Map.class)));
        }

        if(metrics != null)
            builder = builder.metrics(metrics);

        List entityIds = getAs(map, MetricsData.ENTITY_IDS, List.class, false);
        if(entityIds != null)
            builder = builder.entityIds(entityIds);

        Integer limit = getAs(map, MetricsData.LIMIT, Integer.class, false);
        if(limit != null)
            builder = builder.limit(limit);

        return  builder.build();
    }

    /**
     * Creates an inventory data item.
     * @param map The configuration properties
     * @return The widget data
     */
    private InventoryData getInventoryData(Map map)
    {
        List sources = getAs(map, InventoryData.SOURCES, List.class);
        if(sources == null)
            sources = new ArrayList();

        Map filters = getAs(map, InventoryData.FILTERS, Map.class, false);
        if(filters == null)
            filters = new LinkedHashMap();

        return InventoryData.builder()
            .sources(sources)
            .filters(filters)
            .build();
    }

    /**
     * Creates a threshold data item.
     * @param map The configuration properties
     * @return The widget threshold
     */
    private Threshold getThreshold(Map map)
    {
        Threshold.Builder builder = Threshold.builder();
        Integer red = getAs(map, Threshold.RED, Integer.class);
        Integer yellow = getAs(map, Threshold.YELLOW, Integer.class, false);
        if(red != null)
            builder = builder.red(red);
        if(yellow != null)
            builder = builder.yellow(yellow);
        return builder.build();
    }

    /**
     * Creates a metric item.
     * @param map The configuration properties
     * @return The metric
     */
    private Metric getMetric(Map map)
    {
        List values = getAs(map, Metric.VALUES, List.class, false);
        Metric.Builder builder = Metric.builder()
            .name(getAs(map, Metric.NAME, String.class, false));
        if(values != null)
            builder = builder.values(values);
        return builder.build();
    }

    /**
     * Creates a traffic light.
     * @param map The configuration properties
     * @return The traffic light
     */
    private TrafficLight getTrafficLight(Map map)
    {
        return TrafficLight.builder()
            .id(getAs(map, TrafficLight.ID, String.class))
            .title(getAs(map, TrafficLight.TITLE, String.class, false))
            .subtitle(getAs(map, TrafficLight.SUBTITLE, String.class, false))
            .states(getTrafficLightStates(getAs(map, TrafficLight.STATES, List.class)))
            .build();
    }

    /**
     * Creates a set of traffic light states.
     * @param map The configuration properties
     * @return The traffic light states
     */
    private List getTrafficLightStates(List states)
    {
        if(states == null)
            return null;

        List ret = new ArrayList();
        for(Object state : states)
        {
            if(state instanceof Map)
            {
                Map map = (Map)state;

                TrafficLightState.Builder builder = TrafficLightState.builder()
                    .type(getAs(map, TrafficLightState.TYPE, String.class));

                Integer min = getAs(map, TrafficLightState.MIN, Integer.class);
                if(min != null)
                    builder = builder.min(min);

                Integer max = getAs(map, TrafficLightState.MAX, Integer.class);
                if(max != null)
                    builder = builder.max(max);

                ret.add(builder.build());
            }
        }

        if(ret.size() == 0)
            throw new IllegalArgumentException("traffic light must contain at least one state");

        return ret;
    }

    /**
     * Adds common fields to the widget.
     * @param builder The widget builder
     * @param map The configuration properties
     * @return The widget
     */
    private Widget.Builder getWidget(Widget.Builder builder, String title, Map map)
    {
        builder = builder
            .title(title)
            .notes(getAs(map, Presentation.NOTES, String.class, false));

        Integer accountId = getAs(map, Widget.ACCOUNT_ID, Integer.class);
        if(accountId != null)
            builder = builder.accountId(accountId);

        Object layout = map.get(Widget.LAYOUT);
        if(layout instanceof Map)
            builder = builder.layout(getLayout((Map)layout));
        else if(layout instanceof List)
            builder = builder.layout(getLayout((List)layout));

        return builder;
    }

    /**
     * Returns a widget layout object.
     * @param map The layout properties as a map
     * @return The layout
     */
    private Layout getLayout(Map map)
    {
        Layout.Builder builder = Layout.builder();

        Integer row = getAs(map, Layout.ROW, Integer.class);
        if(row != null)
            builder = builder.row(row);

        Integer column = getAs(map, Layout.COLUMN, Integer.class);
        if(column != null)
            builder = builder.column(column);

        Integer width = getAs(map, Layout.WIDTH, Integer.class, false);
        if(width != null)
            builder = builder.width(width);

        Integer height = getAs(map, Layout.HEIGHT, Integer.class, false);
        if(height != null)
            builder = builder.height(height);

        return builder.build();
    }

    /**
     * Returns a widget layout object.
     * @param list The layout properties as a list
     * @return The layout
     */
    private Layout getLayout(List list)
    {
        Layout.Builder builder = Layout.builder();
        if(list.size() >= 2)
            builder = builder.position(list.get(0), list.get(1));
        if(list.size() >= 4)
            builder = builder.size(list.get(2), list.get(3));
        return builder.build();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy