Erlang: Dialyzer HTML Reports using rebar3
4 min read

Erlang: Dialyzer HTML Reports using rebar3

How I made a custom rebar3 plugin to generate HTML reports for dialyzer warnings

Introduction

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:

Rebar3 Dialyzer Default Output
rebar3 dialyzer output

This is a good starting point, but it's not very useful in some cases:

  1. If you have lots of warnings, this output covers several screens, and it becomes difficult to parse through everything.
  2. 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.

So, I build a rebar3 plugin that generates a nicely formatted color HTML report from the dialyzer output. The plugin can be found on hex.pm, or on github.

Usage

Make sure you're using rebar3 version 3.15 or later.

  1. Add the plugin to your rebar.config:
{plugins, [
    %% from hex
    {rebar3_dialyzer_html, "0.2.0"}
    
    %% or, latest from git
    {rebar3_dialyzer_html, {git, "https://github.com/srijan/rebar3_dialyzer_html.git", {branch, "main"}}}
]}.
rebar.config snippet

2. Select raw format for the dialyzer warnings file generated by rebar3 (this is a new flag available from rebar 3.15):

{dialyzer, [
    {output_format, raw}
]}.
rebar.config snippet

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:

Dialyzer HTML Report Sample
Sample HTML report for dialyzer

How I built the plugin

rebar3 dialyzer

The rebar3 built-in dialyzer plugin does the following:

  1. Runs dialyzer with the options configured in rebar.config
  2. Converts the output to ANSI color format and write it to console (it has a custom function for this formatting)
  3. 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:

  1. 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.

  2. 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.

HTML output

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:

  1. rebar3 uses the cf library to convert tagged strings to ANSI color codes. I can use something like dependency injection to replace the cf module 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.

  2. 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.

  3. Convert using a JS library after page load. I found a javascript library called ansi_up which can convert ANSI codes to HTML color tags, or it can add CSS classes that can be styled as required.

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 dialyzer:format/2.

Future Improvements

  1. I want to remove the dependency on Javascript, and want to write/use a pure Erlang library that can convert the ANSI codes to HTML.
  2. 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.
  3. This can even run git commands 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.
  4. Maybe make the format plug-able so the report can be saved in any JSON / XML or any custom format.

Let me know in the comments below, or on twitter/github if you have any suggestions for this plugin.

Follow me on Twitter