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

org.gridkit.jvmtool.AbstractThreadDumpSource Maven / Gradle / Ivy

There is a newer version: 0.23
Show newest version
/**
 * Copyright 2017 Alexey Ragozin
 *
 * 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.gridkit.jvmtool;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.gridkit.jvmtool.cli.CommandLauncher;
import org.gridkit.jvmtool.codec.stacktrace.ThreadSnapshotEvent;
import org.gridkit.jvmtool.codec.stacktrace.ThreadSnapshotEventPojo;
import org.gridkit.jvmtool.event.ErrorHandler;
import org.gridkit.jvmtool.event.Event;
import org.gridkit.jvmtool.event.EventMorpher;
import org.gridkit.jvmtool.event.EventReader;
import org.gridkit.jvmtool.event.ShieldedEventReader;
import org.gridkit.jvmtool.stacktrace.analytics.CachingFilterFactory;
import org.gridkit.jvmtool.stacktrace.analytics.ParserException;
import org.gridkit.jvmtool.stacktrace.analytics.PositionalStackMatcher;
import org.gridkit.jvmtool.stacktrace.analytics.ThreadEventFilter;
import org.gridkit.jvmtool.stacktrace.analytics.ThreadSnapshotFilter;
import org.gridkit.jvmtool.stacktrace.analytics.TimeRangeChecker;
import org.gridkit.jvmtool.stacktrace.analytics.TraceFilterPredicateParser;

import com.beust.jcommander.Parameter;

public abstract class AbstractThreadDumpSource extends AbstractEventDumpSource {

    @Parameter(names={"-tf", "--trace-filter"}, required = false, description="Apply filter to traces before processing. Use --ssa-help for more details about filter notation")
    private String traceFilter = null;

    @Parameter(names={"-tt", "--trace-trim"}, required = false, description="Positional filter trim frames to process. Use --ssa-help for more details about filter notation")
    private String traceTrim = null;

    @Parameter(names={"-tn", "--thread-name"}, required = false, description="Thread name filter (Java RegEx syntax)")
    private String threadName = null;

    
    public AbstractThreadDumpSource(CommandLauncher host) {
        super(host);
    }
        
    public EventReader getFilteredReader() {
        if (traceFilter == null && traceTrim == null && threadName == null && timeRange == null) {
            return getUnclassifiedReader();
        }
        else {
            EventReader reader = getUnclassifiedReader();
            if (threadName != null) {
                reader = reader.morph(new ThreadNameFilter(threadName));
            }
            if (timeRange != null) {
                String[] lh = timeRange.split("[-]");
                if (lh.length != 2) {
                    host.fail("Invalid time range '" + timeRange + "'", "Valid format yyyy.MM.dd_HH:mm:ss-yyyy.MM.dd_HH:mm:ss hours and higher parts can be ommited");
                }
                TimeRangeChecker checker = new TimeRangeChecker(lh[0], lh[1], timeZone);
                reader = reader.morph(new TimeFilter(checker));
            }
            try {
                CachingFilterFactory factory = new CachingFilterFactory();
                if (traceFilter != null) {
                    ThreadSnapshotFilter ts = TraceFilterPredicateParser.parseFilter(traceFilter, factory);
                    reader = reader.morph(new ThreadEventFilter(ts));
                }
                if (traceTrim != null) {
                    final PositionalStackMatcher mt = TraceFilterPredicateParser.parsePositionMatcher(traceTrim, factory);
                    reader = reader.morph(new TrimProxy() {

                        @Override
                        public ThreadSnapshotEvent morph(ThreadSnapshotEvent event) {
                            int n = mt.matchNext(event, 0);
                            if (n >= 0) {
                                trimPoint = n;
                                return super.morph(event);
                            }
                            else {
                                return null;
                            }
                        }
                    });
                }
                return reader;
            }
            catch(ParserException e) {
                throw host.fail("Failed to parse trace filter - " + e.getMessage() + " at " + e.getOffset() + " [" + e.getParseText() + "]");
            }
        }
    }

    protected abstract List inputFiles();
    
    public EventReader getUnclassifiedReader() {

    	EventReader rawReader = getRawReader();

        ShieldedEventReader shielderReader = new ShieldedEventReader(rawReader, ThreadSnapshotEvent.class, new ErrorHandler() {
            @Override
            public boolean onException(Exception e) {
                System.err.println("Stream reader error: " + e);
                return true;
            }
        });

        return shielderReader;
    }    
        
    static class TimeFilter implements EventMorpher {
        
        TimeRangeChecker checker;
        
        public TimeFilter(TimeRangeChecker checker) {
            this.checker = checker;
        }

        @Override
        public ThreadSnapshotEvent morph(ThreadSnapshotEvent event) {
            return checker.evaluate(event.timestamp()) ? event : null;
        }
    }

    static class ThreadNameFilter implements EventMorpher {
        
        Matcher matcher;
        
        public ThreadNameFilter(String regex) {
            this.matcher = Pattern.compile(regex).matcher("");
        }

        @Override
        public ThreadSnapshotEvent morph(ThreadSnapshotEvent event) {
            return evaluate(event) ? event : null;
        }

        protected boolean evaluate(ThreadSnapshotEvent event) {
            if (event.threadName() != null) {
                matcher.reset(event.threadName());
                return matcher.matches();
            }
            else {
                return false;
            }
        }
    }
    
    static class TrimProxy implements EventMorpher {
        
        protected ThreadSnapshotEventPojo snap = new ThreadSnapshotEventPojo();
        protected int trimPoint = 0;
        
        public TrimProxy() {
        }

        @Override
        public ThreadSnapshotEvent morph(ThreadSnapshotEvent event) {
            snap.loadFrom(event);
            snap.stackTrace(event.stackTrace().fragment(0, trimPoint));
            return snap;
        }
    }    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy