diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# Version 1.1
+
+* **BREAKING CHANGE:** Exceptions are now logged _at the throw site_ by
+  default now when possible, with level `Warning`. See the changelog for
+  `di-monad-1.1`.
+
+
 # Version 1.0.1
 
 * COMPILER ASSISTED BREAKING CHANGE: We don't export `Di`, `DiT` nor `MonadDi`
diff --git a/di.cabal b/di.cabal
--- a/di.cabal
+++ b/di.cabal
@@ -1,5 +1,5 @@
 name: di
-version: 1.0.1
+version: 1.1
 author: Renzo Carbonara
 maintainer: renλren.zone
 copyright: Renzo Carbonara 2017-2018
@@ -26,6 +26,7 @@
   exposed-modules: Di
   build-depends:
     base >=4.9 && <5.0,
+    containers,
     df1,
     di-core,
     di-df1,
diff --git a/lib/Di.hs b/lib/Di.hs
--- a/lib/Di.hs
+++ b/lib/Di.hs
@@ -8,9 +8,9 @@
 -- but if you find these are not sufficient for your particular use case, please
 -- refer to other libraries of the /di logging ecosystem/ such as
 -- [di-core](https://hackage.haskell.org/package/di-core),
--- [di-monad](https://hackage.haskell.org/package/di-core),
--- [di-handle](https://hackage.haskell.org/package/di-core), or
--- [di-df1](https://hackage.haskell.org/package/di-core), and you are likely
+-- [di-monad](https://hackage.haskell.org/package/di-monad),
+-- [di-handle](https://hackage.haskell.org/package/di-handle), or
+-- [di-df1](https://hackage.haskell.org/package/di-df1), and you are likely
 -- to find a compatible and composable solution there. For this reason, staring
 -- with this package rather than one of the those other lower-level packages is
 -- always recommended.
@@ -39,6 +39,8 @@
 --
 -- * We commit logs to the outside world by printing them to 'System.IO.stderr'.
 --
+-- * Exceptions are logged at their throw site (see 'Di.Core.onException').
+--
 -- You will notice that some of the functions in this module mention the types
 -- 'Df1.Level', 'Df1.Path' and 'Df1.Message', and some other functions
 -- talk about @level@, @path@ and @msg@ type variables. This is
@@ -99,6 +101,8 @@
 
 import Control.Monad.Catch as Ex
 import Control.Monad.IO.Class (MonadIO)
+import Data.Sequence (Seq)
+import Data.String (fromString)
 
 import qualified Df1
 import qualified Di.Core
@@ -137,6 +141,7 @@
 --                    'Di.Df1.Monad.push' "handler" $ do
 --                       'Di.Df1.Monad.attr' "client-address" clientAddress $ do
 --                          'Di.Df1.Monad.info' "Connection established"
+--                          'Ex.throwM' ('userError' "Oops!")
 -- @
 --
 -- That program will render something like this to 'System.IO.stderr' (in colors!):
@@ -146,8 +151,12 @@
 -- 2018-05-06T19:48:06.195041422Z \/initialization NOTICE Starting web server
 -- 2018-05-06T19:48:06.195052862Z \/server port=80 INFO Listening for new clients
 -- 2018-05-06T19:48:06.195059084Z \/server port=80 \/handler client%2daddress=192%2e168%2e0%2e25%3a32528 INFO Connection established
+-- 2018-05-06T19:48:06.195059102Z \/server port=80 \/handler client%2daddress=192%2e168%2e0%2e25%3a32528 exception=user%20error%20(Oops!) WARNING Exception thrown
 -- @
 --
+-- Notice that by default, /all/ exceptions thrown using 'Ex.throwM' or
+-- 'Di.throw' are logged /at their throw site/ with 'Df1.Warning' level.
+--
 -- (Unrelated: Notice how /df1/ escapes pretty much all punctuation characters.
 -- This is temporal until /df1/ is formalized and a more limited set of
 -- punctuation characters is reserved.)
@@ -169,5 +178,16 @@
   -> m a -- ^
 new act = do
   commit <- Di.Handle.stderr Di.Df1.df1
-  Di.Core.new commit act
+  Di.Core.new commit $ \di -> do
+     act (Di.Core.onException exceptionHandler di)
+
+exceptionHandler
+  :: Ex.SomeException
+  -> Maybe (Df1.Level, Seq Df1.Path, Df1.Message)
+{-# INLINE exceptionHandler #-}
+exceptionHandler = \se -> Just
+  ( Df1.Warning
+  , pure (Df1.Attr "exception" (fromString (show se)))
+  , "Exception thrown"
+  )
 
