= Gerrit Inspector

== NAME
Gerrit Inspector - Interactive Jython environment for Gerrit

== SYNOPSIS
[verse]
--
_java_ -jar gerrit.war _daemon_
  -d <SITE_PATH>
  [--enable-httpd | --disable-httpd]
  [--enable-sshd | --disable-sshd]
  [--console-log]
  [--slave]
  -s
--

== DESCRIPTION
Runs the Gerrit network daemon on the local system as described
in the link:pgm-daemon.html[Daemon documentation], additionally
starting an interactive Jython shell for inspection
and troubleshooting of live data of the Gerrit instance.

CAUTION: Gerrit Inspector works directly on instances of Java Virtual
Machine objects and it is possible to read and write instance
members as well as invoke Java functions. Access is granted
also to 'private' and 'protected' members. Therefore it is possible
to introduce changes to the internal state of the system in
an inconsistent way. Care must be taken not to break the running system
and/or destroy the data.

== INSTALLATION

Gerrit Inspector requires Jython library ('jython.jar') to be installed
in the '$site_path/lib' directory. Jython, a Python interpreter for
the Java Virtual Machine, can be obtained from the http://www.jython.org/
website. Only 'jython.jar' file is needed, installation of Jython libraries
is optional. Gerrit Inspector has been tested with Jython 2.5.2 but
might work an earlier version.

== STARTUP

During startup Jython examines Java libraries found on the classpath.
While libraries are inspected a large amount of messages is displayed on the console:

----
*sys-package-mgr*: processing new jar, '/home/user/.gerritcodereview/tmp/gerrit_4890671371398741854_app/sshd-core-0.5.1-r1095809.jar'
----

After this a system-wide embedded initialization script is started. This script
is contained in the gerrit's WAR archive. This script produces output similar to
the following on the console:

----
"Shell" is "com.google.gerrit.pgm.shell.JythonShell@61644f2d"
"m" is "com.google.gerrit.lifecycle.LifecycleManager@6f03b248"
"ds" is "com.google.gerrit.server.schema.DataSourceProvider@6b3592c"
"schk" is "com.google.gerrit.server.schema.SchemaVersionCheck@5e8cb9bd"

Welcome to the Gerrit Inspector
Enter help() to see the above again, EOF to quit and stop Gerrit
----

Then an optional user startup script is processed. It should be
located in the gerrit user home directory as '.gerritcodereview/Startup.py'.

This script can access all variables defined in the system (such
as the ones displayed by the initialization script as shown above).
Variables and functions defined by the startup scripts are available for
the interactive interpreter.

When interactive interpreter exits (by issuing EOF on the command line),
a whole Gerrit instance is shut down gracefully.

== USING THE INTERPRETER

Gerrit Inspector launches Jython interpreter in the context of the Gerrit
Java Virtual Machine. All core facilities of the Jython (and Python)
language are available to the user.

Additional facilities can be provided, for example a 'Lib' directory from the
Jython distribution can be installed under '$site_path/lib/Lib' to provide
access to many standard Python modules. Jython can also use additional Java
classes and libraries and most of the Python modules and scripts.

The Inspector has by default access to classes and object instances available
in the Java Virtual Machine. Objects are introspected and *private* and *protected*
members are also available.

For more information on using Jython, especially with regards to its limitations
in interfacing to the Java Virtual Machine, please refer to the
http://www.jython.org/[Jython documentation].

After successful initialization it is possible to examine components of
Java packages, classes and live instances.

----
>>> import com.google.inject
>>> dir(com.google.inject)
['AbstractModule', 'Binder', 'Binding', 'BindingAnnotation', 'ConfigurationException', 'CreationException', 'Exposed', 'Guice', 'ImplementedBy', 'Inject', 'Injector', 'Key', 'MembersInjector', 'Module', 'OutOfScopeException', 'PrivateBinder', 'PrivateModule', 'ProvidedBy', 'Provider', 'Provides', 'ProvisionException', 'Scope', 'ScopeAnnotation', 'Scopes', 'Singleton', 'Stage', 'TypeLiteral', '__name__', 'assistedinject', 'binder', 'internal', 'matcher', 'name', 'servlet', 'spi', 'util']
>>> type(com.google.inject)
<type 'javapackage'>
>>> dir(com.google.inject.Guice)
['__class__', '__copy__', '__deepcopy__', '__delattr__', '__doc__',
'__eq__', '__getattribute__', '__hash__', '__init__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__str__', '__unicode__', 'class', 'clone', 'createInjector',
'equals', 'finalize', 'getClass', 'hashCode', 'notify', 'notifyAll',
'registerNatives', 'toString', 'wait']
----

Startup script provides some convenient variables to access some global Gerrit components,
for example a connection to the review database is kept open:

----
>>> ds
org.apache.commons.dbcp.BasicDataSource@61db2215
>>> ds.driverClassName
u'org.postgresql.Driver'
>>> ds.dataSource
org.apache.commons.dbcp.PoolingDataSource@23226fe1
>>> ds.dataSource.connection
jdbc:postgresql://localhost/reviewdb, UserName=rv, PostgreSQL Native Driver
----

It is also possible to interact with the ORM layer:

----
>>> db = schk.schema.open()
>>> db
com.google.gerrit.reviewdb.server.ReviewDb_Schema_GwtOrm$$28@24cbbdf3
>>> db.getDialect()
com.google.gwtorm.schema.sql.DialectPostgreSQL@4de07d3e
>>> for x in db.patchSets().iterateAllEntities():
...     print x
...
[PatchSet 1,1]
[PatchSet 2,1]
[PatchSet 3,1]
[PatchSet 4,1]
[PatchSet 5,1]
[PatchSet 6,1]
[PatchSet 7,1]
[PatchSet 8,1]
[PatchSet 6,2]
>>> for x in db.patchComments().iterateAllEntities():
...     print x
com.google.gerrit.reviewdb.client.PatchLineComment@5381298a
com.google.gerrit.reviewdb.client.PatchLineComment@44ce4dda
com.google.gerrit.reviewdb.client.PatchLineComment@44594680
>>> dir(com.google.gerrit.reviewdb.client.PatchLineComment)
['Key', 'STATUS_DRAFT', 'STATUS_PUBLISHED', 'Status', '__class__',
'__copy__', '__deepcopy__', '__delattr__', '__doc__', '__eq__',
'__getattribute__', '__hash__', '__init__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__',
'__unicode__', 'author', 'class', 'clone', 'equals', 'finalize',
'getAuthor', 'getClass', 'getKey', 'getLine', 'getMessage',
'getParentUuid', 'getSide', 'getStatus', 'getWrittenOn', 'hashCode',
'key', 'line', 'lineNbr', 'message', 'notify', 'notifyAll',
'parentUuid', 'registerNatives', 'setMessage', 'setSide', 'setStatus',
'side', 'status', 'toString', 'updated', 'wait', 'writtenOn']
>>> for x in db.patchComments().iterateAllEntities():
...     print x.status, x.line, x.message
...
P 2 I like it!
P 2 more
P 1 better
----

A built-in *help()* function provides values of global variables
defined in the interpreter:

----
>>> help()
"schk" is "com.google.gerrit.server.schema.SchemaVersionCheck@5e8cb9bd"
"ds" is "com.google.gerrit.server.schema.DataSourceProvider@6b3592c"
"m" is "com.google.gerrit.lifecycle.LifecycleManager@6f03b248"
"Shell" is "com.google.gerrit.pgm.shell.JythonShell@61644f2d"
"d" is "com.google.gerrit.pgm.Daemon@28a3f689"

Welcome to the Gerrit Inspector
Enter help() to see the above again, EOF to quit and stop Gerrit
----

Java and Python exceptions are intercepted by the Inspector:
----
>>> import java.lang.RuntimeException
>>> raise java.lang.RuntimeException("Exiting")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:532)
        at org.python.core.PyReflectedConstructor.constructProxy(PyReflectedConstructor.java:210)

java.lang.RuntimeException: java.lang.RuntimeException: Exiting
>>>
----

To exit the interpreter, use EOF character (Ctrl-D on Unix systems, Ctrl-Z on Windows).

It is also possible to shut down the JVM by using *System.exit()*

----
>>> import java.lang.System
>>> java.lang.System.exit(1)
----

And Gerrit should shut down all its subsystems and exit:

----
[2012-04-17 15:31:08,458] INFO  com.google.gerrit.pgm.Daemon : caught shutdown, cleaning up
----

== TROUBLESHOOTING

Gerrit Inspector is logging to the Gerrit error log.

A successful startup is indicated in the logfile:

----
  [2012-04-17 13:43:44,888] INFO  com.google.gerrit.pgm.shell.JythonShell : Jython shell instance created.
----

If 'jython.jar' library is not available, Gerrit refuses to start when given *-s* option:

----
[2012-04-17 13:57:29,611] ERROR com.google.gerrit.pgm.Daemon : Unable to start daemon
com.google.inject.ProvisionException: Guice provision errors:

1) Error injecting constructor, java.lang.UnsupportedOperationException: Cannot create Jython shell: Class org.python.util.InteractiveConsole not found
     (You might need to install jython.jar in the lib directory)
  at com.google.gerrit.pgm.shell.JythonShell.<init>(JythonShell.java:47)
  while locating com.google.gerrit.pgm.shell.JythonShell
  while locating com.google.gerrit.pgm.shell.InteractiveShell
----

Errors during processing of the startup script, 'Startup.py', are logged
to the error log:

----
[2012-04-17 14:20:30,558] INFO  com.google.gerrit.pgm.shell.JythonShell : Jython shell instance created.
[2012-04-17 14:20:38,005] ERROR com.google.gerrit.pgm.shell.JythonShell : Exception occurred while loading file Startup.py :
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at com.google.gerrit.pgm.shell.JythonShell.runMethod0(JythonShell.java:112)
        at com.google.gerrit.pgm.shell.JythonShell.execFile(JythonShell.java:194)
        at com.google.gerrit.pgm.shell.JythonShell.reload(JythonShell.java:178)
        at com.google.gerrit.pgm.shell.JythonShell.run(JythonShell.java:152)
        at com.google.gerrit.pgm.Daemon.run(Daemon.java:190)
        at com.google.gerrit.pgm.util.AbstractProgram.main(AbstractProgram.java:67)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at com.google.gerrit.launcher.GerritLauncher.invokeProgram(GerritLauncher.java:167)
        at com.google.gerrit.launcher.GerritLauncher.mainImpl(GerritLauncher.java:91)
        at com.google.gerrit.launcher.GerritLauncher.main(GerritLauncher.java:49)
        at Main.main(Main.java:25)
Caused by: Traceback (most recent call last):
  File "/home/user/.gerritcodereview/Startup.py", line 1, in <module>
    Test
NameError: name 'Test' is not defined
----

Those errors are non-fatal. System and user scripts can be loaded again
by issuing the following command in the Gerrit Inspector console:

----
Shell.reload()
----

== LOGGING
Error and warning messages from the server are automatically written
to the log file under '$site_path/logs/error_log'.

Output and error messages (including Java and Python exceptions)
resulting from interactive work are logged to the console.

== KNOWN ISSUES
The Inspector does not yet recognize Google Guice bindings.

[IMPORTANT]
Using the Inspector may void your warranty.

GERRIT
------
Part of link:index.html[Gerrit Code Review]

SEARCHBOX
---------
