Background:
I want to log user activities on Eclipse, for example, what git repositories the users cloned, when did merge conflicts happened, and so on.
I came up with using the OpenJ9 -Xtrace option. First, to test the OpenJ9 -Xtrace option capabilities, I made the following options with OpenJ9: Xtrace Option Builder, and add these options to eclipse.ini to log cloned git repositories.
-Xtrace:none,maximal={mt{entry},mt{exit},mt{exception}},methods={org/eclipse/jgit/api/CloneCommand.setURI(),org/eclipse/jgit/api/CloneCommand.call()},output="C:\tmp\mytrace.trc"
-Xjit:exclude={org/eclipse/jgit/api/CloneCommand.setURI*|org/eclipse/jgit/api/CloneCommand.call*}
org/eclipse/jgit/api/CloneCommand.setURI() is a method to set a URI
for cloned repository in EGit/JGit.
org/eclipse/jgit/api/CloneCommand.call() is a method to clone the
specified repository.
Then I launched Eclipse with -clean option, clone a repository, and exit Eclipse.
I converted mytrace.trc with traceformat command, and got this output in mytrace.trc.fmt:
Trace Formatted Data
Time (UTC) Thread ID Tracepoint ID Type Tracepoint Data
07:56:41.541990300 *0x0000000001fafe00 mt.0 Entry >org/eclipse/jgit/api/CloneCommand.setURI(Ljava/lang/String;)Lorg/eclipse/jgit/api/CloneCommand; bytecode method, this = 0x7f9788a98
07:56:41.541991900 0x0000000001fafe00 mt.6 Exit <org/eclipse/jgit/api/CloneCommand.setURI(Ljava/lang/String;)Lorg/eclipse/jgit/api/CloneCommand; bytecode method
07:56:41.542010000 0x0000000001fafe00 mt.0 Entry >org/eclipse/jgit/api/CloneCommand.call()Lorg/eclipse/jgit/api/Git; bytecode method, this = 0x7f9788a98
07:56:46.512616000 0x0000000001fafe00 mt.6 Exit <org/eclipse/jgit/api/CloneCommand.call()Lorg/eclipse/jgit/api/Git; bytecode method
07:56:47.631399600 0x0000000001fafe00 dg.262 Debug ***** Thread termination - trace purged *****
This output shows setURI() method has an argument (Ljava/lang/String;), but there is no URI that JGit cloned.
Question:
How can I dump the content of method argument with OpenJ9 Xtrace option?
How can I dump the content of method argument with OpenJ9 Xtrace
option?
Your option only enables entry, exit, and exception method trace tracepoints. Method arguments are printed under a different tracepoint. If you use this option instead you should see the additional trace entries containing the arguments.
However, while the values of primitive arguments are shown in the trace, when the argument is an object you will only see the address of the object on the Java heap. For example, when tracing calls to *.println() you will see something like this:
15:31:13.710 0x33acc00 mt.18 - this: java/io/PrintStream#00000000FFF04AE0 method arguments: (java/lang/String#00000000E0002768)
My understanding is that the limitation is due to the architecture of the Xtrace engine, and the performance impact of resolving objects such as Strings and storing them in the trace buffers.
While addresses can be extremely useful for locating objects of interest in the Java heap, for example when using Eclipse Memory Analyzer to look at an associated system dump, Xtrace cannot provide the functionality you are aiming for.
A alternative approach would be to use a Java agent to modify (instrument) the org/eclipse/jgit/api/CloneCommand class at runtime to add logging code to the .setURI() method.
Related
I am trying to get the hang of jsonnet files. So far all I have is hard-coded values but what if I wanted to get the hostname for a Java application. For example in Java I would just do:
String hostName = System.getenv("HOSTNAME");
But obviously I can't just have a key-value pair like the following JSON in a jsonnet file.
{name: "hostname", value:System.getenv("HOSTNAME")}
I need a bit of help in understanding how I can do this.
I have looked up std.extvar(x) but the examples I look at just arent clear to me for whatever reason. Is this method relevant? Otherwise, I'm not really sure.
Jsonnet requires all parameters to be passed explicitly. To use a hostname in your Jsonnet code, you need to pass it to the interpreter. For example you can run it as follows:
❯ jsonnet --ext-str "HOSTNAME=$HOST" foo.jsonnet
foo.jsonnet:
std.extVar('HOSTNAME')
You can also use top-level-arguments mechanism to a similar effect (top-level-arguments are passed as function arguments to the evaluated script.
Please see: https://jsonnet.org/learning/tutorial.html#parameterize-entire-config for more in-depth explanation of these features.
FYI not being able to just grab any environment variable or access the system directly is very much by design. The result of Jsonnet evaluation depends only on the code and explicitly passed parameters. This has a lot of benefits, such as the following:
You can easily evaluate on another machine, even on a completely different platform and get exactly the same result.
You are never locked in to configuration on any particular machine – you can always pass any parameters on any machine (very useful for development and debugging).
Avoiding surprises – the evaluation won't break one day, because some random aspect of local configuration changed and some deep part of the code happens to depend on it – all parameters are accounted for.
I'm developing a plug-in for the Eclipse platform. This plug-in will be used to give information about the line of Java source code currently being debugged.
When debugging a Java program, as you hit a breakpoint, Eclipse switches to the standard Debug perspective. Inside this perspective, apart from the standard Console output, the stack trace and various other views, you can see source code of the Java program currently being debugged. Inside this 'source code view', you can see a highlighted line, which is the line of code currently being debugged/evaluated. This highlighted line of code is what I want to access.
Assuming I know when the debugger is running (I assess that through a DebugBreakpointListener class that implements IJavaBreakpointListener), I need to 'ask questions' to the debugger. What, I imagine, I will need, is to somehow ask the debugger directly either for the line of code it is currently highlighting/debugging/evaluating or for the line number of the said line of code.
I'm making a static access to the JDIDebugModel to add the Java Breakpoint Listener:
JDIDebugModel.addJavaBreakpointListener(new DebugBreakpointListener);
I thought I could access the debugger with static references to JDIDebugPlugin but I've yet to find what I'm looking for.
At Part 3 of this research paper, the authors suggested that:
The Eclipse Java debugger is built upon the API of Java Debug Interface (JDI), which is part of the Java Development Toolkit. This API enables adding requests to monitor JVM events such as BreakpointEvent. When an event occurs, the debugger gets a notification and the thread in which this event took place can be obtained. For each frame in the stack trace of this thread the following information can be obtained:
• The source Java file in which the execution at this frame has taken place (or null if the source is not available).
• The method and line number (if available).
• The this object or null if the method is static.
The Eclipse debugger uses this information when a breakpoint is hit. It shows the stack trace for the suspended thread in the ”Debug” view. For the selected frame in this trace, Eclipse highlights the corresponding line number in its source file, and displays the this variable in the ”Variables” view.
This bulletpoint-listed things are exactly what I'm looking for.
Unfortunately, I can't find detailed documentation on how to 'plug in' to the debugger.
If someone can give me information, point me to information or a sample code, or maybe provide me with contact information of someone from the Eclipse JDI project, it would be immensely appreciated.
Thanks in advance.
------Update & Answer:------
With the help of greg-449's answer, I did exactly what I wanted to do. Here's what I did:
The aformentioned breakpoint listener I wrote implements the interface method breakpointHit, which is as follows:
#Override
public int breakpointHit(IJavaThread thread, IJavaBreakpoint breakpoint) {
System.out.println("Just hit a breakpoint!");
// Save pointers to the thread & breakpoint for future use.
return 0;
}
With the pointers to the thread and breakpoint objects saved in one of my objects, I could query them to get up-to-date information on the state of the frame stack, the thread and about the particular breakpoint that I've hit. I can get the namea dn path of the class the debugger is currently debugging by calling:
IStackFrame topStackFrame = thread.getTopStackFrame();
int debuggedLineNumber = topStackFrame.getLineNumber();
String debuggedClassPath = topStackFrame.getLaunch().getSourceLocator().getSourceElement(thread.getTopStackFrame()).toString();
This was exactly what I was looking for. I imagine I will need to read the source code files manually, run them through a tokenizer by having the 'newline' character as a delimiter and get the corresponding token to read that specific line.
There is a huge amount of information available in the IJavaThread and IJavaBreakpoint arguments passed to the breakpointHit method of the IJavaBreakpointListener which should contain this information.
I think for breakpoints which have a line number (not all do) the IJavaBreakpoint argument also implements ILineBreakpoint containing the line information.
I have found in docs for jstack:
jstack prints Java stack traces of Java threads for a given Java process or core
file or a remote debug server. For each Java frame, the full class name, method name,
'bci' (byte code index) and line number, if available, are printed. With the -m
option, jstack prints both Java and native frames of all threads along with the
'pc' (program counter). For each native frame, the closest native symbol to 'pc',
if available, is printed. C++ mangled names are not demangled. To demangle C++
names, the output of this command may be piped to c++filt.
I know frame is element of visual interface, but in this context it seems different?
Search in Google produce links to visual element. It seems that frame is about threading. Does it possible found definition? Thanks.
"frame" in this context refers to a stack frame, not a visual GUI element.
The short explanation is that every method call produces a stack frame, where local variables/results/return values are stored. By following the stack frames of your program, you can learn the current call stack
Here "frame" means stack frame, the parts of a program's call stack. http://en.wikipedia.org/wiki/Call_stack
I'm remote debugging a Java application and (not for the first time) I find myself looking for a value without knowing what variable might hold it (if any at all). This is especially hard to find since I'm stepping through library code rather than my own code, so I was wondering; since eclipse can display the variables currently available on the stack, along with all contained values, is there any way I can search these? Or at the very least dump it out as text somewhere and grep it or something.
I usually do an export to JSON using Jackson's ObjectMapper whenever I find myself into the situation of having to search among a bunch of values caught while debugging. On breakpoint hit, let's say I want to search some string inside a text representation of myObj, which could be some messy POJO deep with nested objects. Just evaluate the following:
org.codehaus.jackson.map.ObjectMapper mapper = new org.codehaus.jackson.map.ObjectMapper();
mapper.writeValue(new java.io.File("/tmp/myObj.json"), myObj);
and then go grep your value inside the file you just created.
YMMV: if you have no idea where to start the search you'll have to iterate through what's available on the stack. Also the JSON representation might not be suitable for every kind of search.
I'm not sure about the feature you are asking for but there is another approach you could take. Assuming you know the general area AND the object you are looking for isn't too common, eclipse supports conditional breakpoints so you could set breakpoints on the end of methods chechking the method variables and object state.
You could try evars. I haven't tried the search function, but it allows expanding and exporting all the variables on the stack to a file, which you can then grep for your value. I installed the latest version into Eclipse manually, i.e. putting the jar in the dropins/plugins directory. Worked for me on Eclipse 3.6.1.
how can i find out which class/method has called the actual method?
You could try to create an exception to get its stacktrace.
Throwable t = new Throwable();
StackTraceElement[] stackTraceElements = t.getStackTrace();
Now stackTraceElement[0] contains the caller of the current method.
But beware (from Throwable.getStackTrace()):
Some virtual machines may, under some
circumstances, omit one or more stack
frames from the stack trace. In the
extreme case, a virtual machine that
has no stack trace information
concerning this throwable is permitted
to return a zero-length array from
this method. Generally speaking, the
array returned by this method will
contain one element for every frame
that would be printed by
printStackTrace.
Here's one way that I've used:
StackTraceElement element=Thread.currentThread().getStackTrace()[3];
String className=element.getClassName();
String methodName=element.getMethodName();
[3] is hardcoded because:
[0] is Thread.dumpThreads()
[1] is Thread.getStackTrace()
[2] is the current method
[3] is the one before the current method
A faster but non-portable solution is to use the following. It does not create a stack trace and just gives you the information you need. However, not all JVMs will have this and future version of Java might not either.
Class callerClass = sun.reflect.Reflection.getCallerClass(2);
You can print a stack trace to do this.
If you want to do this dynamically, I'm not really sure if this is possible (aside from printing and parsing a stack trace dynamically).
You could use a debugger, or a profiler. Netbeans has both, but a lot of other options exists.
Else, if you can modify the code you can throw a new exception() and have a stacktrace printed in the console.
To echo and elaborate on matt b and yishai's comments:
If you are doing this because you are writing a logger or maintaining trace information or some such, okay, cool. I've used stack traces in production code exactly once, and even that was really a debugging issue: We had a problem with database connections not being properly closed, so I modified the "get database connection" function to save the identity of the caller, and then had a periodic sweep to look for dead connections and see where they had been created.
Java's built-in logging function does stack traces so it can write who called the logger to the log file. I worry about the overhead of this as I understand that stack traces are expensive, but whatever.
But if you're doing this because your function is going to behave differently depending on where it was called from, like "if called from class X update customer data else if called from class Y update employee data" or something like that: Really really bad idea. Pass a parameter or write separate functions.