No commit activity in last 3 years
No release in over 3 years
Tools to work with Elm history exports.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 1.16
~> 10.0
 Project Readme

ElmHistoryTools

One of the great aspects of the Elm programming language is its debugger. Because all the possible states of an Elm program are clearly defined and state only changes in response to messages, Elm can track everything that happens -- and make it available to you to debug both.

You can also export this history to a file, allowing your support team and developers to debug a user's session without having to be in the same room. Using a package like ElmRings, you can even capture this data automatically and upload it to your servers for later use.

Of course, once you have that data on your servers, you'll have to work through two challenges:

  1. Security: every keystroke of a user’s password and all the sensitive personal information they enter in your app go into Elm’s history. It’s no good hashing passwords on the user model if another table contains them in plain text — you need to sanitize and secure this data carefully if you store it.
  2. Complicated data structure: the Elm history data is meant to be imported into Elm more than it's meant to be analyzed by humans. If you want to show your support team what happened in a user session in which an error occurred, you need to make that data presentable.

If you, like me, have these problems, you're in the right place.

Installation

Add this line to your application's Gemfile:

gem 'elm_history_tools'

And then execute:

$ bundle

Or install it yourself as:

$ gem install elm_history_tools

Usage

Right now, ElmHistoryTools comes with two utilities:

Sanitizing History

Be careful you don't accidentally expose critical user information -- it's no good hashing passwords on the user model if an Elm history table contains them in plain text. Before storing

How do you actually do this?

ElmHistoryTools::HistorySanitizer allows you to sanitize Elm records and objects. Because these objects are so individual to your application, there's no universal code that can sanitize the data without breaking the structure. (This is why we can't, for instance, just use something like Rails' ParameterFilters.)

Instead, you tell the HistorySanitizer which terms to look for and provide a block that can do the sanitizing:

# let's say you have an Elm object like
# MySecretData "access_token" {password = "myP@ssw0rd", expiration = "tomorrow"}
ElmHistoryTools::HistorySanitizer.sanitize_history(history_data, ["MySecretData", "password"]) do |elm_object_or_record|
  if elm_object_or_record["ctor"] == "MySecretData"
    # replace the access token
    # make sure to return the updated object!
    elm_object_or_record.merge("_0" =>"[FILTERED]")
  else
    # we have the record
    elm_object_or_record.merge("password" => "[FILTERED]")
  end
end

# before: {"ctor" => "MySecretData", "_0" => "access_token", "_1" => {"password" => "myP@ssw0rd", "expiration" => "tomorrow"}}
# after: {"ctor" => "MySecretData", "_0" => "[FILTERED]", "_1" => {"password" => "[FILTERED]", "expiration" => "tomorrow"}}

As you can see, this is neither flexible nor elegant -- unfortunately, that's the nature of the game when you're manipulating the state generated by an Elm program. Elm types may store sensitive data as basic data in the object, which leaves no automated way to detect and replace that information.

Format a History into a Hash

One approach we've found useful for user issues at eSpark Learning has been to skim the history and see if anything looks amiss. Eyeballing the user's actions shows if a student get an unhappy response back from a server, if they were able to they answer any quiz questions, etc., providing a useful context for further debugging.

In order to make sense of data, it has to be presented in a compact and (relatively) human-readable format, which the raw history export is not. (See below for more information on that.) Such cleanup is what the ElmHistoryTools::HistoryFormatter object can do:

# given a JSON history file like
# {"history": [{"ctor": "MessageType", "_0": "Arg1", "_02": {"ctor": "AnotherType"}}, {"ctor":"AnotherMessageType", "_0": "AnotherArg"}]}

ElmHistoryTools::HistoryFormatter.to_simple_hash(JSON.parse(history_json))

# will produce

[
  {"MessageType" => ["Arg1", {"AnotherType" => []}],
  {"AnotherMessageType" => ["AnotherArg"]}
]

You can then easily loop over this data in Ruby to present a readable internal dashboard:

elm-history-dashboard

Elm History Export Format

For more information on the Elm history export format, see this blog post.

Why hashes?

Why hashes?, you might wonder. Why not use arrays (e.g. {"MessageType": ["Arg1", {"AnotherType": []}]} or ["MessageType", "Arg1", ["AnotherType"]])? Wouldn't that be simpler?

Turns out you're not the first person to wonder about it. As @evancz wrote in response to a similar question in 2015:

I believe in the olden times, I did use an array because I just assumed it'd be fast. I later ran some benchmarks and was totally wrong, objects were a lot faster. So I switched everything.

Development

After checking out the repo, run bin/setup to install dependencies. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/arsduo/elm_history_tools. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the ElmHistoryTools project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the Code of Conduct.