/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * 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 org.pentaho.di.core.logging; import java.util.ArrayList; import java.util.List; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.gui.GCInterface; import org.pentaho.di.core.gui.Point; import org.pentaho.di.core.gui.PrimitiveGCInterface.EColor; import org.pentaho.di.core.gui.PrimitiveGCInterface.EFont; import org.pentaho.di.core.gui.Rectangle; import org.pentaho.di.core.metrics.MetricsDuration; public class MetricsPainter { private GCInterface gc; private Long periodStart = null; private Long periodEnd = null; private int barHeight; public class MetricsDrawArea { private Rectangle area; private MetricsDuration duration; public MetricsDrawArea( Rectangle area, MetricsDuration duration ) { this.area = area; this.duration = duration; } public MetricsDuration getDuration() { return duration; } public Rectangle getArea() { return area; } } public MetricsPainter( GCInterface gc, int barHeight ) { this.setGc( gc ); this.barHeight = barHeight; } /** * Draws a metrics tab. * * @param durations * is a list of metrics durations * @return list of drawing areas.Throw IllegalArgumentException in case if input parameter is null or an empty */ public List<MetricsDrawArea> paint( List<MetricsDuration> durations ) { if ( Utils.isEmpty( durations ) ) { throw new IllegalArgumentException(); } int width = getGc().getArea().x - 4; int height = getGc().getArea().y - 4; List<MetricsDrawArea> areas = new ArrayList<MetricsDrawArea>(); // First determine the period // determinePeriod( durations ); if ( periodStart == null || periodEnd == null || periodEnd <= periodStart ) { return areas; // nothing to do; } double pixelsPerMs = (double) width / ( (double) ( periodEnd - periodStart ) ); long periodInMs = periodEnd - periodStart; drawTimeScaleLine( height, pixelsPerMs, periodInMs ); drawDurations( durations, areas, pixelsPerMs ); return areas; } void drawTimeScaleLine( int height, double pixelsPerMs, long periodInMs ) { int log10 = (int) Math.log10( periodInMs ) + 1; int timeLineDistance = (int) Math.pow( 10, log10 - 1 ) / 2; int incrementUnit = Math.max( timeLineDistance, 1 ); for ( int time = timeLineDistance; time <= periodInMs; time += incrementUnit ) { int x = (int) ( time * pixelsPerMs ); getGc().setForeground( EColor.LIGHTGRAY ); getGc().drawLine( x, 0, x, height ); String marker = Integer.toString( time ); Point point = getGc().textExtent( marker ); getGc().setForeground( EColor.DARKGRAY ); getGc().drawText( marker, x - ( point.x / 2 ), 0, true ); } } private void drawDurations( List<MetricsDuration> durations, List<MetricsDrawArea> areas, double pixelsPerMs ) { // set top indent int y = 20; for ( MetricsDuration duration : durations ) { Long realDuration = duration.getEndDate().getTime() - duration.getDate().getTime(); // How many pixels does it take to drawn this duration? // int durationWidth = (int) ( realDuration * pixelsPerMs ); int x = 2 + (int) ( ( duration.getDate().getTime() - periodStart ) * pixelsPerMs ); getGc().setBackground( EColor.BACKGROUND ); getGc().setForeground( EColor.LIGHTBLUE ); getGc().fillGradientRectangle( x, y, durationWidth, barHeight, false ); getGc().setForeground( EColor.BLACK ); getGc().drawRectangle( x, y, durationWidth, barHeight ); areas.add( new MetricsDrawArea( new Rectangle( x, y, durationWidth, barHeight ), duration ) ); LoggingObjectInterface loggingObject = LoggingRegistry.getInstance().getLoggingObject( duration.getLogChannelId() ); String message = duration.getDescription() + " - " + loggingObject.getObjectName() + " : " + duration.getDuration() + "ms"; if ( duration.getCount() > 1 ) { message += " " + duration.getCount() + " calls, avg=" + ( duration.getDuration() / duration.getCount() ); } getGc().setFont( EFont.GRAPH ); getGc().textExtent( message ); getGc().drawText( message, x + 3, y + 4, true ); y += barHeight + 5; } } private void determinePeriod( List<MetricsDuration> durations ) { periodStart = null; periodEnd = null; for ( MetricsDuration duration : durations ) { long periodStartTime = duration.getDate().getTime(); if ( periodStart == null || periodStartTime < periodStart ) { periodStart = periodStartTime; } long periodEndTime = duration.getEndDate().getTime(); if ( periodEnd == null || periodEnd < periodEndTime ) { periodEnd = periodEndTime; } } } // Method is defined as package-protected in order to be accessible by unit tests GCInterface getGc() { return gc; } // Method is defined as package-protected in order to be accessible by unit tests void setGc( GCInterface gc ) { this.gc = gc; } }