Skip to content

Instantly share code, notes, and snippets.

@jhrcek
Last active August 14, 2020 10:12
Show Gist options
  • Select an option

  • Save jhrcek/a6e7766b8b0cb503dea9f08763d20f6d to your computer and use it in GitHub Desktop.

Select an option

Save jhrcek/a6e7766b8b0cb503dea9f08763d20f6d to your computer and use it in GitHub Desktop.
This script prepends timestamps to lines streaming from stdin and prints them to stdout
#!/usr/bin/env stack
-- stack script --resolver lts-16.9 --package conduit,text,mtl
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -Wall #-}
import Conduit (decodeUtf8C, encodeUtf8C, mapMC, runConduit, stdinC, stdoutC, (.|))
import Control.Monad.State.Strict (StateT, evalStateT, get, liftIO, put)
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Word (Word64)
import qualified GHC.Clock as Clock
import Text.Printf
{- This script prepends timestamps to lines streaming from stdin and prints them to stdout
EXAMPLE USAGE: put the script somewhere on your path and pipe stuff via STDIN to it. For example
stack build --no-terminal stack build --no-terminal 2>&1 | timelines.hs
-}
main :: IO ()
main = do
startNanos <- Clock.getMonotonicTimeNSec
evalStateT (prependTime startNanos) startNanos
prependTime :: Word64 -> StateT Word64 IO ()
prependTime startNanos =
runConduit $
stdinC
.| decodeUtf8C
.| mapMC (prependTimestamp startNanos)
.| encodeUtf8C
.| stdoutC
prependTimestamp :: Word64 -> Text -> StateT Word64 IO Text
prependTimestamp startNanos input = do
previousNanos <- get
nanosNow <- liftIO Clock.getMonotonicTimeNSec
let secondsSinceStart = nanosToSeconds $ nanosNow - startNanos
secondsSincePrev = nanosToSeconds $ nanosNow - previousNanos
prevDelta =
let textDelta = printf "+%.3f" secondsSincePrev
in if secondsSincePrev > 10 --TODO make threshold configurable
then highlight textDelta
else textDelta
timeData = printf "%7.3f [%s] " secondsSinceStart prevDelta
put nanosNow
pure $ Text.pack timeData <> input
nanosToSeconds :: Word64 -> Double
nanosToSeconds ns = fromIntegral ns / 1000_000_000
highlight :: String -> String
highlight x = brightRed <> x <> reset
where
brightRed = "\ESC[1;31m"
reset = "\ESC[0m"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment