Dialyzer is a static analysis tool for Erlang that identifies software discrepancies, such as definite type errors, code that has become dead or unreachable because of programming errors, and unnecessary tests, in single Erlang modules or entire (sets of) applications.
Dialyzer is integrated with rebar3 (a build tool for Erlang), and its default output looks like this:
This is a good starting point, but it's not very useful in some cases:
- If you have lots of warnings, this output covers several screens, and it becomes difficult to parse through everything.
- If you run this in some sort of continuous integration (like Jenkins), then the console output is not very friendly.
One way to improve this is to generate an HTML report which can be published/emailed/opened in the browser.
Make sure you're using rebar3 version
3.15 or later.
- Add the plugin to your
2. Select raw format for the dialyzer warnings file generated by rebar3 (this is a new flag available from rebar
3. Run the
dialyzer_html rebar3 command:
$ rebar3 dialyzer_html ===> Generating Dialyzer HTML Report ===> HTML Report written to _build/default/dialyzer_report.html
Here's how the report looks:
How I built the plugin
The rebar3 built-in dialyzer plugin does the following:
- Runs dialyzer with the options configured in
- Converts the output to ANSI color format and write it to console (it has a custom function for this formatting)
- Converts the output to basic format (using built-in
dialyzer:format/2) and write it to a dialyzer_warnings file.
I wanted to find out the easiest way to get a nicely formatted HTML report, ideally without forking the rebar3 project itself.
The first thing I needed was a way to save the raw (machine parse-able) dialyzer output to the warnings file instead of the default formatted output. For this, I submitted a new feature to the rebar3 project, and it introduces a new config to enable this. So, this plugin needs rebar3 version
3.15 or later.
Plugin vs Escript
Next, to actually parse and output the HTML file, I would need to run some Erlang code. There are two options I considered:
- Escript called from Makefile/wrapper
This option works okay, but we cannot re-use any rebar3 internal function or State. I wanted to use rebar3's own custom function for formatting the dialyzer warnings, so decided to not go with this option.
- Custom rebar3 plugin
Doing it this way makes it easy for anyone to use, and I can re-use things already implemented in rebar3 itself. So, I decided to use this option.
Now, in the custom rebar3 plugin, I needed to convert the ANSI color-coded output given by
rebar_dialyzer_format:format_warnings/2 into something for HTML.
I thought of the following options:
- rebar3 uses the cf library to convert tagged strings to ANSI color codes. I can use something like dependency injection to replace the
cfmodule with my own module so that the tagged strings are directly converted to HTML without even going to the intermediate ANSI color-coded format.
This method seemed very hacky, so I decided not to pursue it. But, if rebar3 makes the dialyzer format interface configurable, I can reevaluate this approach.
- Convert by writing a library in Erlang for ANSI code to HTML tags conversion.
There is a library called ansi_to_html in elixir - but didn't want to add a huge dependency like that.
But writing a new Erlang library to do this can be a future optimization.
I opted for approach #3 because it was the easiest. I also grouped the warnings by app name so that all warnings for a single app are in one place, and the report includes the number of warnings per app.
Also, if the JS library could not be loaded (for example due to no internet, or any security headers), then it will still show the basic formatted output using
- Ideally, rebar3 itself can separate the dialyzer warning parsing and formatting into different functions, and make it possible to override the formatting function so that any plugin can pass its own formatting function into the dialyzer plugin.
- This can even run
gitcommands in the shell to figure out if any lines changed in the most recent commit involve a warning, and maybe highlight them especially in the report. This can be useful CI reports on pull requests.
- Maybe make the format plug-able so the report can be saved in any JSON / XML or any custom format.