/* * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the Classpath exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.btrace.dtrace; import java.io.File; import java.io.IOException; import org.opensolaris.os.dtrace.*; import com.sun.btrace.CommandListener; import com.sun.btrace.comm.Command; import com.sun.btrace.comm.ErrorCommand; import com.sun.btrace.comm.MessageCommand; /** * Simple wrapper class around DTrace/Java API. This * wrapper accepts a BTrace command listener, DTrace file * or string and DTrace macro arguments. The events from * DTrace are wrapped as BTrace command instances and given * to the listener. * * @author A. Sundararajan */ public class DTrace { /** * Submits a D-script from given file and passes given * argument array as DTrace macro arguments. The events * from DTrace are wrapped as BTrace commands and listener * given is notified. * * @param file D-script file to submit * @param args DTrace macro arguments * @param listener BTrace command listener that is notified */ public static void submit(File file, String[] args, CommandListener listener) throws DTraceException, IOException { Consumer cons = newConsumer(args, listener); cons.compile(file, args); start(cons, listener); } /** * Submits a D-script string and passes the given * argument array as DTrace macro arguments. The events * from DTrace are wrapped as BTrace commands and listener * given is notified. * * @param program D-script as a string * @param args DTrace macro arguments * @param listener BTrace command listener that is notified */ public static void submit(String program, String[] args, CommandListener listener) throws DTraceException { Consumer cons = newConsumer(args, listener); cons.compile(program, args); start(cons, listener); } private static void start(Consumer cons, final CommandListener listener) throws DTraceException { cons.enable(); cons.go(new ExceptionHandler() { @Override public void handleException(Throwable th) { try { listener.onCommand(new ErrorCommand(th)); } catch (IOException ioexp) { ioexp.printStackTrace(); } } }); } private static Consumer newConsumer(String[] args, final CommandListener listener) throws DTraceException { Consumer cons = new LocalConsumer(); cons.addConsumerListener(new ConsumerAdapter() { private void notify(Command cmd) { try { listener.onCommand(cmd); } catch (IOException ioexp) { ioexp.printStackTrace(); } } @Override public void consumerStarted(ConsumerEvent ce) { notify(new DTraceStartCommand(ce)); } @Override public void consumerStopped(ConsumerEvent ce) { Consumer cons = (Consumer)ce.getSource(); Aggregate ag = null; try { ag = cons.getAggregate(); } catch (DTraceException dexp) { notify(new ErrorCommand(dexp)); } StringBuilder buf = new StringBuilder(); if (ag != null) { for (Aggregation agg : ag.asMap().values()) { String name = agg.getName(); if (name != null && name.length() > 0) { buf.append(name); buf.append('\n'); } for (AggregationRecord rec : agg.asMap().values()) { buf.append('\t'); buf.append(rec.getTuple()); buf.append(" "); buf.append(rec.getValue()); buf.append('\n'); } } } String msg = buf.toString(); if (msg.length() > 0) { notify(new MessageCommand(msg)); } notify(new DTraceStopCommand(ce)); cons.close(); } @Override public void dataReceived(DataEvent de) { notify(new DTraceDataCommand(de)); } @Override public void dataDropped(DropEvent de) { notify(new DTraceDropCommand(de)); } @Override public void errorEncountered(ErrorEvent ee) throws ConsumerException { try { super.errorEncountered(ee); } catch (ConsumerException ce) { notify(new DTraceErrorCommand(ce, ee)); throw ce; } } }); // open DTrace Consumer cons.open(); // unused macro arguments are fine cons.setOption(Option.argref, ""); // if no macro arg passed use "" or NULL cons.setOption(Option.defaultargs, ""); // allow empty D-scripts cons.setOption(Option.empty, ""); // be quiet! equivalent to DTrace's -q cons.setOption(Option.quiet, ""); // undefined user land symbols are fine cons.setOption(Option.unodefs, ""); // allow zero matching of probes (needed for late loading) cons.setOption(Option.zdefs, ""); try { int pid = Integer.parseInt(args[0]); cons.grabProcess(pid); } catch (Exception ignored) { } return cons; } }