nri-prelude-0.6.0.6: A Prelude inspired by the Elm programming language
Safe HaskellNone
LanguageHaskell2010

Log

Description

This module is dedicated to logging information in production, to help understand what the application is doing when something goes wrong. This sets it apart from the Debug module which provide helpers for debugging problems in development.

This module does not have an Elm counterpart.

Synopsis

Logging

debug :: HasCallStack => Text -> [Context] -> Task e () Source #

A log message that is probably only useful in development, or when we're really confused about something and need ALL THE CONTEXT.

In addition to a log message you can pass additional key-value pairs with information that might be relevant for debugging.

debug "Computation partially succeeded" [context "answer" 2]

info :: HasCallStack => Text -> [Context] -> Task e () Source #

A log message useful for when things have gone off the rails. We should have a ton of messages at this level. It should help us out when we're dealing with something hard.

In addition to a log message you can pass additional key-value pairs with information that might be relevant for debugging.

info "I added 1 and 1" [context "answer" 2]

warn :: HasCallStack => Text -> [Context] -> Task e () Source #

A log message when something went wrong, but it did not go wrong in a way to totally break the thing we're doing. These should be triaged and fixed soon, but aren't show-stoppers.

In addition to a log message you can pass additional key-value pairs with information that might be relevant for debugging.

warn "This field was sent, but we're gonna deprecate it!" []

error :: HasCallStack => Text -> [Context] -> Task e () Source #

A log message when we can't continue with what we were trying to do because of a problem.

In addition to a log message you can pass additional key-value pairs with information that might be relevant for debugging.

error "The user tried to request this thing, but they aren't allowed!" []

withContext :: HasCallStack => Text -> [Context] -> Task e b -> Task e b Source #

Mark a block of code as a logical unit by giving it a name. This name will be used in logs and monitoring dashboards, so use this function to help debug production problems.

In addition to a name you can pass this function a list of context. A context is a key-value pair you want to attach to all logs made inside of the block of code wrapped.

Example usage:

withContext "play-music" [context "artist" "The Beatles"] <| do
  -- your code here!

Additionally, this function adds an entry to our homemade stack trace for if something errors. Why not use the built-in stack trace? Well, the built-in stack trace only records a frame if you add Stack.HasCallStack => to the function, so if we want a full stack trace, we need to add that to literally all functions. Instead of doing that, we will use withContext to collect the stack trace, since it is used fairly often already. It will not be complete either, but it's the best we can do without too much trouble.

context :: (Show a, ToJSON a) => Text -> a -> Context Source #

A key-value pair that can be added to a log context. All log expressions within the context will always log this key-value pair.

Secrets

data Secret a Source #

Distinguishes data that is secret and should not be logged.

Please be careful when defining or altering instances for this data type. There's a good chance we will leak credentials, PII, or other equally sensitive information.

Instances

Instances details
Functor Secret Source # 
Instance details

Defined in Log

Methods

fmap :: (a -> b) -> Secret a -> Secret b #

(<$) :: a -> Secret b -> Secret a #

Applicative Secret Source # 
Instance details

Defined in Log

Methods

pure :: a -> Secret a #

(<*>) :: Secret (a -> b) -> Secret a -> Secret b #

liftA2 :: (a -> b -> c) -> Secret a -> Secret b -> Secret c #

(*>) :: Secret a -> Secret b -> Secret b #

(<*) :: Secret a -> Secret b -> Secret a #

Eq a => Eq (Secret a) Source # 
Instance details

Defined in Log

Methods

(==) :: Secret a -> Secret a -> Bool #

(/=) :: Secret a -> Secret a -> Bool #

Show (Secret a) Source #

N.B. This instance of Show is not law abiding.

This instance exists because we sometimes use Secret in data types that have to derive Show (due to other constraints on those data types).

This is not a pattern to follow; it's an exception.

Instance details

Defined in Log

Methods

showsPrec :: Int -> Secret a -> ShowS #

show :: Secret a -> String #

showList :: [Secret a] -> ShowS #

ToJSON (Secret a) Source # 
Instance details

Defined in Log

mkSecret :: a -> Secret a Source #

Wrap a value in a secret to prevent it from being accidentally logged.

Debug.log "Logging a secret" (mkSecret "My PIN is 1234")
--> Logging a secret: Secret *****

unSecret :: Secret a -> a Source #

Retrieve the original value from a secret. Be very careful with this and ask yourself: is there really no way I can pass this value on as a secret further before I need to unwrap it?

The longer a value is wrapped in a Secret, the smaller the odds of it accidentally being logged.

For use in observability modules

data Context where Source #

Extra information to attach to a log message. It is passed a string key defining what the data is and a value with a ToJSON instance.

Constructors

Context :: (Show a, ToJSON a) => Text -> a -> Context 

Instances

Instances details
Show Context Source # 
Instance details

Defined in Log