diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,24 @@
+# Changelog
+
+`ldap-scim-bridge` uses [PVP][1]-compatible versioning.
+The changelog is available [on GitHub][2].
+
+## 0.3
+
+- Better error logging. (#11)
+- Allow mapping the scim `displayName` attribute. (#14)
+
+## 0.2
+
+* Fix: add `./examples/wire-server/` to hackage distro.
+
+## 0.1
+
+* Working for one non-trivial use-case.  See `./examples/wire-server/`
+
+## 0.0.0.0
+
+* Initially created.
+
+[1]: https://pvp.haskell.org
+[2]: https://github.com/fisx/ldap-scim-bridge/releases
diff --git a/ldap-scim-bridge.cabal b/ldap-scim-bridge.cabal
--- a/ldap-scim-bridge.cabal
+++ b/ldap-scim-bridge.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.4
 name:                ldap-scim-bridge
-version:             0.2
+version:             0.3
 synopsis:            See README for synopsis
 description:         See README for description
 homepage:            https://github.com/fisx/ldap-scim-bridge
@@ -12,12 +12,12 @@
 copyright:           (c) 2021 wire.com
 category:            System
 build-type:          Simple
-extra-doc-files:     examples/wire-server/run.sh
+extra-doc-files:     README.md
+                     CHANGELOG.md
+extra-source-files:  examples/wire-server/run.sh
                      examples/wire-server/conf1.yaml
                      examples/wire-server/conf2.yaml
                      examples/wire-server/runlog
-extra-source-files:  README.md
-
 tested-with:         GHC == 8.8.3
 
 source-repository head
diff --git a/src/LdapScimBridge.hs b/src/LdapScimBridge.hs
--- a/src/LdapScimBridge.hs
+++ b/src/LdapScimBridge.hs
@@ -199,6 +199,7 @@
 
 instance Aeson.FromJSON Mapping where
   parseJSON = Aeson.withObject "Mapping" $ \obj -> do
+    fdisplayName <- obj Aeson..: "displayName"
     fuserName <- obj Aeson..: "userName"
     fexternalId <- obj Aeson..: "externalId"
     mfemail <- obj Aeson..:? "email"
@@ -209,17 +210,27 @@
             go mp (k, b) = Map.alter (Just . maybe [b] (b :)) k mp
 
     pure . Mapping . listToMap . catMaybes $
-      [ Just (fuserName, mapUserName fuserName),
+      [ Just (fdisplayName, mapDisplayName fdisplayName),
+        Just (fuserName, mapUserName fuserName),
         Just (fexternalId, mapExternalId fexternalId),
         (\femail -> (femail, mapEmail femail)) <$> mfemail
       ]
     where
+      -- The name that shows for this user in wire.
+      mapDisplayName :: Text -> FieldMapping
+      mapDisplayName ldapFieldName = FieldMapping "displayName" $
+        \case
+          [val] -> Right $ \usr -> usr {Scim.displayName = Just val}
+          bad -> Left $ WrongNumberOfAttrValues ldapFieldName "1" (Prelude.length bad)
+
+      -- Really, not username, but handle.
       mapUserName :: Text -> FieldMapping
       mapUserName ldapFieldName = FieldMapping "userName" $
         \case
           [val] -> Right $ \usr -> usr {Scim.userName = val}
           bad -> Left $ WrongNumberOfAttrValues ldapFieldName "1" (Prelude.length bad)
 
+      mapExternalId :: Text -> FieldMapping
       mapExternalId ldapFieldName = FieldMapping "externalId" $
         \case
           [val] -> Right $ \usr -> usr {Scim.externalId = Just val}
@@ -290,8 +301,8 @@
       (Left errs, Right _) -> Left errs
       (Left errs, Left err) -> Left ((entry, err) : errs)
 
-connectScim :: ScimConf -> IO ClientEnv
-connectScim conf = do
+connectScim :: Logger -> ScimConf -> IO ClientEnv
+connectScim lgr conf = (`catch` logErrors) $ do
   let settings =
         if scimTls conf
           then HTTP.tlsManagerSettings
@@ -299,6 +310,10 @@
   manager <- HTTP.newManager settings
   let base = BaseUrl Http (scimHost conf) (scimPort conf) (scimPath conf)
   pure $ mkClientEnv manager base
+  where
+    logErrors (SomeException e) = do
+      lgr Error $ "could not connect to scim peer: " <> show e
+      throwIO e
 
 isDeletee :: LdapConf -> SearchEntry -> Bool
 isDeletee conf = case ldapDeleteOnAttribute conf of
@@ -309,7 +324,7 @@
 
 updateScimPeer :: Logger -> BridgeConf -> IO ()
 updateScimPeer lgr conf = do
-  clientEnv <- connectScim (scimTarget conf)
+  clientEnv <- connectScim lgr (scimTarget conf)
   let tok = Just . scimToken . scimTarget $ conf
   ldaps :: [SearchEntry] <-
     either (throwIO . ErrorCall . show) pure =<< listLdapUsers (ldapSource conf) (ldapSearch (ldapSource conf))
@@ -460,4 +475,9 @@
   myconf :: BridgeConf <- parseCli
   lgr :: Logger <- mkLogger (logLevel myconf)
   lgr Debug $ show (mapping myconf)
-  updateScimPeer lgr myconf
+  updateScimPeer lgr myconf `catch` logErrors lgr
+  where
+    logErrors :: Logger -> SomeException -> IO a
+    logErrors lgr (SomeException e) = do
+      lgr Fatal $ "uncaught exception: " <> show e
+      throwIO e
