Diagnosing running applications is oftentimes a very tedious task. To make this experience as smooth as possible, let's look at how CUBA can help us. After that, we will take a look at extended features that we can use, like an interactive Groovy console.
Investigating a Running System Is Hard
When you try to resolve an issue in a running system, it can be hard to effectively get the information you need to understand the problem. First of all, you need to understand the unclear bug descriptions you might have got from your customers. Sometimes, it is reproducible in your test system; other times, it is not.
In these cases, you have to somehow get further information from the running system. If you run your software on your own, you have to get access to the corresponding log files or application to see the error in real life or at least to see the impact it has on the software. When doing boxed software, the situation is even worse because the barrier to get to the required information is higher and the process is more tedious.
You might already live in this fancy microservices/cloud world where you have full control over your running software. In this case, you probably have automated environments in place that will raise the visibility of insights into the systems.
If not, you are in this weird place where trying to identify the actual problem feels like trying to hit a target with a bullet in a totally dark room. The majority of software developers has been more or less in this situation from time to time.
If you can identify with this situation or with the one in the below GIF, you might be interested in seeing another tool in the runtime debugger’s toolset:
Fixing a bug in production is like...
What CUBA Brings to the Table
CUBA already brings a lot of built-in features that will make your experience as a debugger much easier. Let’s have a short look at those features.
The first thing that comes to my mind is the entity inspector (Administration > Entity Inspector). This is a screen where you can have CRUD screens for every entity in your system. These browse-and-edit screens are dynamically assembled based on your definition in the entity model.
Looking up entity instances with the entity inspector.
Let's say you have a customer with orders and other attributes. Entity Inspector will show you a list of customers. When you edit a customer, all direct attributes will be shown as FieldGroup or Compositions, and OneToMany or ManyToMany Associations will be displayed as tables. This is pretty much how Studio will scaffold these screens.
It is a very good way to see exactly what entity instances are in your current system so that you can get a better understanding of where the problem lies. This is especially true for entities that would otherwise have no user interface.
If you want to take a shortcut to fix a problem with the data, you can use Entity Inspector to easily create and update entity instances so that correct values are in place. Most of the time, this is more of a temporary fix; nevertheless, it is super valuable to have such a tool at hand if necessary.
Besides the above-described feature, it is actually a really good tool to get an insight on how certain things of the platform work. In the above screenshot, you can see an XML attribute of the
sec$Filter entity that will put you in the situation of getting to know how the filter mechanism internally stores the filter of the corresponding component.
Inspect Log Files
The next very important thing is to have access to the server log files that have been created through logback. CUBA comes with a UI for accessing those files. You can get access to those through Administration > Server Log.
The server log screen shows the content of the log files.
Besides seeing the content, you can also configure the settings of logging at runtime. If you need to have a higher logging level for one of your classes or are not interested in certain platform logging information, you can just adjust the settings.
Changing the settings will only affect the running application, not the file (
logback.xml) where it originated from. This means that after a restart of the application, the settings will be back to the state of the
The third feature of CUBA in regards of runtime debugging is a JMX console. JMX stands for Java Management Extensions and is a powerful tool to inspect running Java applications as well as executing code in an application.
There are several tools in the Java ecosystem, like JConsole, that allow connecting to a remote Java application (via a GUI or command line tools) and executing JMX calls. CUBA mainly enhances this feature through a UI that will display all managed beans that can be called, as well as the methods on these beans.
Actually, there are some other features of a CUBA application that will make your life as an application debugger easier, like Performance Statistics or Screen Profiler. I will not go through all of them, but you might want to scan through the Administration menu to get an idea of what can be done.
Although we are in a pretty good position with this, there are some missing gaps. Let's take a look at what those are and what solutions can be used to have even more tools in your hands.
Advanced Problem Solving via Runtime Diagnose
When I was working in Grails land, there was (and still is) a really cool plugin called the Grails console. It's basically an interactive REPL for a running application. It has a web UI, so it is possible to write code in this UI and execute it on the fly. This can be used for totally different purposes:
- Manually adjust the Log4j settings.
- Insert data into the running system.
- Execute the business logic you wrote in services.
- Shut down the Tomcat server.
While some of these features are pretty cool, others are really scary (from a security point of view), so this plugin has to be used with caution and properly secured. Or like Spider-Man likes to phrase it, with great power comes great responsibility.
The Grails Console for CUBA
I recently created an application component that took the ideas from the grails console and transferred it to CUBA island.
You can find it up on GitHub here.
Actually, this was just the starting point because I took the chance to look a little bit deeper in the topic of runtime diagnosis and came up with three different areas of features that are useful for analyzing problems in a running system.
1. Groovy Console for Ad-Hoc Debugging and Diagnosis
Groovy console in CUBA.
The Groovy console allows you to interactively inspect the running application. You enter a Groovy script and execute it in an ad hoc fashion. This obviously requires access to the running system.
The code gets executed in the core module of the application. Therefore, all CUBA beans are at your fingertips. Here are some examples of what you can do with it:
- Insert/update data through CUBA's Data Manager.
- Execute middleware beans to get diagnose information or trigger certain business logic.
- Correct data that has been introduced through a bug in your application.
- Check configurations.
- And more!
There are different results of the Groovy script (displayed in the different tabs). The actual result of the script (meaning the return value of the last statement) is displayed in the first tab. The Stacktrace tab displays the stack trace of a possible exception that occurs during script execution. The tab executed script shows the executed script. For more information, take a look at the documentation.
These results can be downloaded as a ZIP file that will represent the tabs with the corresponding information.
2. SQL Console for Ad-Hoc Debugging and Diagnosis
SQL console in CUBA.
The SQL console allows you to interactively interact with the database using raw SQL statements. You enter an SQL script and execute it in an ad-hoc fashion.
Note: For normal data diagnosis, the Entity Inspector is oftentimes more user-friendly, even for debugging purposes. It's preferable to use the SQL console in the entity inspector if you want to access data across tables using joins.
Results of a SQL statement are displayed in a table in the result tab. The result can be downloaded using the Excel button in the Results tab.
The execution of SQL statements can be restricted. By default, only
SELECT statements are allowed. For more information, see the corresponding documentation.
3. Diagnose Wizard for Non-Interactive Use Cases
Diagnose Wizard will guide the user through the different steps.
The last part is the Diagnose Wizard. This option is relevant if you as a developer or customer support person don’t have direct access to the running application because of security reasons or because it is boxed software that is running out of your control. You could send your counterpart on the customer side a text file that the user should execute in the Groovy/SQL console, but this process is fairly insecure as well as error prone.
In these cases, you can send the person a ZIP file (as a black box) and tell them to upload this file in the diagnose wizard. The person will be guided through the different steps, executed the scripts and gets back the execution results (as a zip file) that should be handed back to you.
Tighten the Bug-Report Feedback Loop
Let’s look at the alternative we have in these scenarios. When the customer tells you that something strange happened in the application, you’ll ask them a handful of questions to get a rough idea what category of error this is, if it is a bug at all or more a misunderstanding of the application, etc.
After that, you might ask for the log files to take a closer look. Depending on how fast this information can be provided, you'll be waiting for some time. After you get the log files, you really should pray to the debugging god that you have good logging messages in places as well as properly configured logging. If you are lucky, you'll see some null pointer exception with a stack trace from which you can start your investigation. Other times, you don’t see much. So you get back to your customer, ask them to adjust the logging settings and try to reproduce the error. After another round trip, you might have more luck. Every step involves some emails or phone calls with a lot of context switching on both sides.
I don't think I have to describe the process any further. The bottom line is that this is a situation that occurs sometimes, but nobody really wants to be in this error-prone and tedious situation.
To tighten this feedback loop a little, you can use the workflow by the diagnose wizard since it gives you more direct feedback. The best situation in this regard would be the ad hoc Groovy/SQL console because the developer feedback is immediate. But this is not always possible and the Diagnose Wizard allows you to find a middle ground in this scenario.
With the built-in CUBA features as well as the Runtime Diagnose application component, you are able to get pretty good insights into your running applications.
This has been my first official open-source project, and although it is not a brand new idea, working on it has been a great experience. I hope it will give developers of CUBA applications another tool in their debugging toolsets.
If you have any questions and or improvement ideas, raise an issue on GitHub or comment below.