If I'm going to put a program into production, there are several things I need that program to do in order to consider it "operationalized" – that is, running and maintainable in a measurable and verifiable way by both engineers and operations staff. For my purposes, an operationalized program must:
- Be able to log at multiple levels (ex: debug, warning, etc.).
- Be able to collect and share metrics/statistics about the types of work the program is doing and how long that work is taking. Ideally, the collected metrics are available in a format that's compatible with commonly-used monitoring tools like Ganglia, or can be so munged.
- Be configurable, ideally via a system that allows configured properties in running programs to be updated without restarting said programs.
- Be deployable to remote servers in a repeatable way.
In the Scala world, there are good libraries for dealing with at least the first three requirements. Examples:
- Logula for logging.
- Metrics or Ostrich for collecting and reporting metrics.
- Configgy or Fig for configuration.
As for deployment, one approach taken in the Scala world is to bundle together the bytecode and libraries that comprise one's program with something like assembly-sbt, then push the resulting bundle (a "fat JAR") to remote servers with a tool like Capistrano that executes commands in parallel over SSH. This isn't a problem that necessitates language-specific tools, but I'm curious if such a tool exists in the Haskell community.
There are probably Haskell libraries that provide the traits I've described above. I'd like to know which of the available libraries are considered "best"; that is, which are most mature, well-maintained, commonly used in the Haskell community, and exemplary of Haskell best practices.
If there are any other libraries, tools, or practices around making Haskell code "production-ready", I'd love to know about those as well.
This is a great question! Here's a first cut.
hslogger is easily the most popular logging framework.
I'm not aware of any standardized reporting tools, however, extracting reports from
+RTS -s
streams (or via profiling output flags) has been something I've done in the past.You can get this in machine-readable format too:
Ideally you could attach to a running GHC runtime over a socket and look at these GC stats interactively, but currently that's not super easy (needs an FFI bindings to the "rts/Stats.h" interface). You can attach to a process using
ThreadScope
and monitor GC and threading behavior.Similar flags are available for incremental, logged time and space profiling, which can be used for monitoring (e.g. these graphs can be built incrementally).
hpc
collects a lot of statistics about program execution, via itsTix
type, and people have written tools to log by time-slice what code is executing.Several tools are available for this, you can do xmonad-style state reloading; or move up to code hotswapping via
plugins
* packages orhint
. Some of these are more experimental than others.Galois recently released
cabal-dev
, which is a tool for doing reproducible builds (i.e. dependencies are scoped and controlled).I would echo everything Don said and add a few general bits of advice.
For example, two additional tools and libraries you might want to consider:
-Wall
Those are both targeted at code quality.
As a coding practice, avoid Lazy IO. If you need streaming IO, then go with one of the iteratee libraries such as enumerator. If you look on Hackage you'll see libraries like http-enumerator that use an enumerator style for http requests.
As for picking libraries on hackage it can sometimes help to look at how many packages depend on something. Easily see the reverse dependencies of a package you can use this website, which mirrors hackage:
If your application ends up doing tight loops, like a web server handling many requests, laziness can be an issue in the form of space leaks. Often this is a matter of adding strictness annotations in the right places. Profiling, experience, and reading core are the main techniques I know of for combating this sort of thing. The best profiling reference I know of is Chapter 25 of Real-World Haskell.
Example of ConfigFile: