Monitoring Socket

  4 posts   Feedicon  
Replies: 3 - Last Post: May 20, 2010 08:43
by: rdruilhe
showing 1 - 4 of 4
 
Posted: May 18, 2010 14:16 by rdruilhe
Hi,

I just discovered BTrace and I think it could help me monitoring a java application (Hadoop).

In this way, I started using some examples and more precisly I am trying to use SocketMonitor (SocketMonitor.java).

But I have some problems using this file and I am not able to solve them.

Here the output :

java.lang.ClassCastException: [B cannot be cast to java.io.InputStream
	at java.io.FileInputStream.$btrace$com$sun$btrace$samples$SocketMonitor$onRead(FileInputStream.java:84)
	at java.io.FileInputStream.read(FileInputStream.java)
	at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
	at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
	at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
	at java.io.InputStreamReader.read(InputStreamReader.java:167)
	at java.io.BufferedReader.fill(BufferedReader.java:136)
	at java.io.BufferedReader.read(BufferedReader.java:157)
	at java.io.StreamTokenizer.read(StreamTokenizer.java:483)
	at java.io.StreamTokenizer.nextToken(StreamTokenizer.java:527)
	at sun.awt.X11GraphicsEnvironment.registerFontDir(X11GraphicsEnvironment.java:764)
	at sun.java2d.SunGraphicsEnvironment$2.run(SunGraphicsEnvironment.java:210)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.java2d.SunGraphicsEnvironment.<init>(SunGraphicsEnvironment.java:127)
	at sun.awt.X11GraphicsEnvironment.<init>(X11GraphicsEnvironment.java:204)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
	at java.lang.Class.newInstance0(Class.java:355)
	at java.lang.Class.newInstance(Class.java:308)
	at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:68)
	at java.awt.Window.init(Window.java:379)
	at java.awt.Window.<init>(Window.java:432)
	at java.awt.Frame.<init>(Frame.java:403)
	at javax.swing.JFrame.<init>(JFrame.java:202)
	at org.viewer.SimpleViewer.<init>(SimpleViewer.java:26)
	at org.viewer.SimpleViewer.<init>(SimpleViewer.java:21)
	at org.viewer.SimpleViewer.main(SimpleViewer.java:77)


I am using it on two distincts applications and I have the same problem (on line 84). I tried to modify the file but it seems I can't call method others than from BTraceUtils (I was thinking to test the size of args).

Thanks,

Regards,
 
Posted: May 19, 2010 08:21 by m_hess
Hi,

about the "can't call method others than from BTraceUtils". That is correct, as long you use BTrace in safe mode. You can add a paramter "unsafe=true" to your javaagent line (the one you added to your java call), and then you are free to use whatever you want. But I think you should be careful with that. Even if whatever "unsafe" thing you do, does not break your application, it might still harm your performance, e.g. by introducing heavy GC pressure because of frequent object allocation.

You probably should also have a look at the btrace usage guide, which states a list of the restrictions the are in place for any Btrace Probe. (http://kenai.com/projects/btrace/pages/UserGuide). The BTraceUtils class holds a huge number of helper methods, so I think most of the "usual" stuff you want to do, can be achieved in safe mode.

About that exception itself. Well, it indeed looks strange on first sight. The line number 84 should refer to the source of the probe, which you linked. Looking at that Proble, I would say everything is fine. What actually happens, is that a byte array (that is what I make up from [B ) is tried to be casted into an InputStream. The strange thing about this, is that according to example AllCalls3.java, the content of the AnyArgs array should be:

// contents of args array:
// [0] - this for the method call
// [1] - textual representation of the method
// [2]..[n] - original method call arguments

So, given the matching rules of that probe method (which clearly states the InputStream) and if everything is working correctly, args[0] should indeed be holding an instance of InputStream.

Maybe, this is a problem with BTrace itself. I suggest, you retry the probing, but exchange the failing probe method's current code, with a simple

printArray(args);

That should show you, what really is in the AnyArgs[] during runtime.

bye, Michael
 
Posted: May 19, 2010 09:36 by Jaroslav Bachorik
Regarding the CCE - the source from the DZone is targeted towards BTrace 1.0 syntax which didn't support annotations for @Self, @Return, @ProbedClassName etc.
In BTrace 1.1+ the AnyType[] argument will hold strictly the method parameters. Special arguments are accessed by using the mentioned annotations.
It seems that the explanation in AllCalls3.java sample slipped my attention when I was changing samples for the new syntax. I'll fix it ASAP.

The correct script should look like this:

package sockets;

import com.sun.btrace.AnyType;
import com.sun.btrace.aggregation.Aggregation;
import com.sun.btrace.aggregation.AggregationFunction;
import com.sun.btrace.annotations.*;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import static com.sun.btrace.BTraceUtils.*;

@BTrace
public class SocketMonitor {

    private static Map<Object,Socket> streamMap = newWeakMap();

    /**
     * A helper aggregation instance summing Data-In and Data-Out per socket
     */
    private static Aggregation socketDataSum = newAggregation(AggregationFunction.SUM);

    @Property
    /**
     * dataIn will get published as a JMX property of the btrace/SocketMonitor bean
     */
    private static AtomicLong dataIn = newAtomicLong(0L);
    @Property
    /**
     * dataOut will get published as a JMX property of the btrace/SocketMonitor bean
     */
    private static AtomicLong dataOut = newAtomicLong(0L);

    @TLS
    /**
     * A thread safe helper variable to keep the instance of a Socket
     * that getInput/OutputStream method is applied to
     */
    private static Socket currentSocket;
    @TLS
    /**
     * A thread safe helper variable to keep the instance of an InputStream
     * that read method is applied to
     */
    private static InputStream currentInputStream;

    /**
     * Intercept the entry to the getInput/OutputStream method call
     * Store the Socket instance in currentSocket variable
     */
    @OnMethod(clazz = "+java.net.Socket", method = "/get(Input|Output)Stream/", location = @Location(Kind.ENTRY))
    public static void onGetStreamEntry(@Self Socket self) {
        currentSocket = self;
    }

    /**
     * Intercept the normal exit of the getInputStream method call
     * Upon the exit the instance of the created InputStream is known
     * so we can bind it with the Socket instance used to obtain the stream
     */
    @OnMethod(clazz = "+java.net.Socket", method = "getInputStream", location = @Location(Kind.RETURN))
    public static void onInputStream(@Return InputStream stream) {
        put(streamMap, stream, currentSocket);
        currentSocket = null;
    }

    /**
     * Intercept the normal exit of the getOutputStream method call
     * Upon the exit the instance of the created OutputStream is known
     * so we can bind it with the Socket instance used to obtain the stream
     */
    @OnMethod(clazz = "+java.net.Socket", method = "getOutputStream", location = @Location(Kind.RETURN))
    public static void onOutputStream(@Return OutputStream stream) {
        put(streamMap, stream, currentSocket);
        currentSocket = null;
    }

    /**
     * Store the InputStream instance used in the read method call
     */
    @OnMethod(clazz = "+java.io.InputStream", method = "read", location = @Location(Kind.ENTRY))
    public static void onRead(@Self InputStream self, AnyType[] args) {
        if (containsKey(streamMap, self)) {
            currentInputStream = self;
        } else {
            currentInputStream = null;
        }
    }

    /**
     * Use the stored InputStream instance to get hold of the defining Socket instance.
     * Then use the byte count available as the result of the method call to update
     * the aggregation and total values
     */
    @OnMethod(clazz = "+java.io.InputStream", method = "read", location = @Location(Kind.RETURN))
    public static void countReadData(@Return int count) {
        if (count > -1 && currentInputStream != null) {
            Socket sck = get(streamMap, currentInputStream);
            addAndGet(dataIn, count);
            addToAggregation(socketDataSum, newAggregationKey(str(sck), "Input"), count);
            currentInputStream = null;
        }
    }

    /**
     * The following three methods intercept and process three different forms of the write method call.
     * The separation is necessary to be able to get hold of strongly typed parameters wchich
     * we can use in oreder to extract valuable information
     */

    @OnMethod(clazz = "+java.io.OutputStream", method = "write", location = @Location(Kind.ENTRY))
    public static void onWrite(@Self Object self, int byteValue) {
        if (containsKey(streamMap, self)) {
            Socket sck = (Socket) get(streamMap, self);
            addAndGet(dataOut, 1L);
            addToAggregation(socketDataSum, newAggregationKey(str(sck), "Output"), 1);
        }
    }

    @OnMethod(clazz = "+java.io.OutputStream", method = "write", location = @Location(Kind.ENTRY))
    public static void onWrite(@Self Object self, byte[] data) {
        if (containsKey(streamMap, self)) {
            Socket sck = (Socket) get(streamMap, self);
            addAndGet(dataOut, data.length);
            addToAggregation(socketDataSum, newAggregationKey(str(sck), "Output"), data.length);
        }
    }

    @OnMethod(clazz = "+java.io.OutputStream", method = "write", location = @Location(Kind.ENTRY))
    public static void onWrite(@Self Object self, byte[] data, int offset, int length) {
        if (containsKey(streamMap, self)) {
            Socket sck = (Socket) get(streamMap, self);
            addAndGet(dataOut, length);
            addToAggregation(socketDataSum, newAggregationKey(str(sck), "Output"), length);
        }
    }

    /**
     * BTrace event handler - when the BTrace engine receives this event
     * it will dump the aggregation data to the client
     */
    @OnEvent("dump_stats")
    public static void dumpData() {
        printAggregation("Summary of the data read by socket", socketDataSum);
    }

    /**
     * BTrace event handler - when received the aggregation data as well as the totals
     * are reset
     */
    @OnEvent("clear_stats")
    public static void reset() {
        println("Resetting collected data...");
        clearAggregation(socketDataSum);
        set(dataIn, 0L);
        set(dataOut, 0L);
        println("Data reset");
    }
}
 
Posted: May 20, 2010 08:43 by rdruilhe
@Jaroslav : your new script doesn't give me errors but it seems I have to modify it in order to get what I want.

With the explanation of m_hess, I have a better understanding of how BTrace works and how to create script. I think I can deal easily with it now.

So thanks for your help Smile
Replies: 3 - Last Post: May 20, 2010 08:43
by: rdruilhe
  • Mysql
  • Glassfish
  • Jruby
  • Rails
  • Nblogo
Terms of Use; Privacy Policy;
© 2010, Oracle Corporation and/or its affiliates
(revision 20120518.3c65429)
 
 
Close
loading
Please Confirm
Close