[Haskell-cafe] Instrumentation without requiring code-level changes?

Saurabh Nanda saurabhnanda at gmail.com
Fri Jan 27 07:15:37 UTC 2017

(copying the mailing list -- I don't think your intention was to keep this
off the mailing list)

I've looked at middleware for Scotty (or any WAI application), but it has
limitations. I want deeper insights about how much time is being spent
where, when serving a web request -- which is why the need to instrument
SQL, Redis, and HTML rendering.

One example that doesn't necessarily need to be in the IO monad is HTML
rendering using Lucid, where the data is being passed separately to it
(standard Controller <> View separation).

Also, if everything needs to be run in MonadIO, what does that do to
fine-grained effect tracking? I wanted to have HasDb, HasRedis, HasEmail
kind of monads (or type-classes) that give me some guarantees about the
**type** of IO interactions a particular function call can do. If I
instrument them and add an additional MonadIO constraint, does it mean any
IO can be lifted into such monads?

It's unfortunate to know that the RTS doesn't have these kind of
instrumentation capabilities built-in. Is it absolutely not possible to do
this at an RTS level?

-- Saurabh.

On Fri, Jan 27, 2017 at 12:32 PM, David Turner <
dct25-561bs at mythic-beasts.com> wrote:

> Hi Saurabh,
> There's no direct equivalent to monkey-patching in Haskell (AFAIK (*)).
> Why not instrument things always? The performance impact is usually quite
> negligible, and the ability to switch instrumentation on at runtime in
> production is sometimes invaluable.
> For instrumenting Scotty (in particular) or WAI-based apps (in general)
> you can instrument things simply by inserting an appropriate `Middleware`,
> a decision that can be deferred until service-startup time, and which
> involves no change to the Scotty-side code.
> There's no equivalent to WAI for database access so I don't have a general
> answer in that case, but typically database APIs have only a few core
> `execute` or `query` functions that are quite straightforward to wrap with
> instrumentation if needs be.
> This all kinda _has_ to be in IO anyway, as you're trying to measure a
> real-world activity. Certainly there's no problem with either Scotty or
> databases in this regard, as they're running in IO. Do you have an example
> where you need instrumentation of a pure (i.e. non-IO) computation? In such
> a case you could use the `unsafePerformIO` escape hatch (like `Debug.Trace`
> does) but you'll have to be very careful to measure what you think you're
> measuring: the language is quite free to reorder computations and avoid
> repeating duplicated computations via referential transparency etc.
> (*) I mean, you could do something with dynamic libs and LD_PRELOAD (the
> original monkey-patching) but please don't!
> Hope that helps,
> David
> On 27 Jan 2017 05:21, "Saurabh Nanda" <saurabhnanda at gmail.com> wrote:
>> (another cross post from Reddit - https://www.reddit.com/r/haske
>> ll/comments/5qfd36/instrumentation_without_required_application/)
>> Is it possible to collect instrumentation data from a Hakell application
>> without requiring the core application to change code? Here are some
>> examples of instrumentation data:
>> * Time taken to serve an HTTP request (not average time, but individual
>> times, for individual requests) along with the incoming request
>> params+headers and outgoing response length.
>> * Time taken to make an SQL query along with the actual query (again, not
>> average times, but individual times, for individual queries)
>> * Time taken to fetch data from Redis along with the Redis command
>> * Time taken to render an HTML page along with path to the HTML file
>> Most dynamic languages (like Ruby) allow monkey-patching OR "decorating"
>> existing functions during runtime. Most instrumentation agents (like
>> Skylight, Newrelic), simply monkey-patch the API surfaces of known
>> libraries to collect this data. Therefore, using these instrumentation
>> agents is a one line code change (just include the gem, or drop the JAR, or
>> whatever).
>> What is the equivalent of this in Haskell?
>> Here's what I've tried so far [1] , but it has the following
>> disadvantages:
>> * Requires changes to the application's cabal file to replace the
>> non-instrumented versions of the libraries with the instrumented version
>> (replace scotty with instrumentedscotty, in my example)
>> * Requires the application to explicitly import the instrumented versions
>> of the libraries (replace import Scotty with import InstrumentedScotty, in
>> my example)
>> * Forces all the code interacting with instrumented APIs to be run in a
>> MonadIO environment - because of the underlying calls to getCurrentTime
>> I'm sure there's a better way, but I couldn't get my hands on it!
>> [1] https://gist.github.com/saurabhnanda/27592da0269bc35569ec6239e1a91b75
>> -- Saurabh.
>> _______________________________________________
>> Haskell-Cafe mailing list
>> To (un)subscribe, modify options or view archives go to:
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> Only members subscribed via the mailman list are allowed to post.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20170127/fb7efec8/attachment.html>

More information about the Haskell-Cafe mailing list