5

This is my scotty app, notice how I am logging requests to the console:

{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
import Network.Wai.Middleware.RequestLogger

import Data.Monoid (mconcat)

main = scotty 3000 $ do
    --log requests to console
    middleware logStdoutDev

    get "/:word" $ do
        beam <- param "word"
        html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]

My scotty app runs behind nginx using the proxy mechanism. This causes the scotty app to log like this:

127.0.0.1 - - [27/Aug/2014:15:12:00 +0000] "GET / HTTP/1.0" 200 - ...

I want the REAL IP ADDRESS to be logged.

I had the same issue in my Node.js/Express apps, where I solved it like this:

Express.js: how to get remote client address

How do I solve this problem in Scotty?

Chris Stryczynski
  • 30,145
  • 48
  • 175
  • 286
stackoverflowuser
  • 1,157
  • 9
  • 18

1 Answers1

10

There's an IPAddrSource data type in wai-extra which originates in the wai-logger package. So, if you want the IP address to come from a header, it looks like you can do something like:

{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
import Network.Wai.Middleware.RequestLogger

import Control.Monad.IO.Class
import Data.Monoid (mconcat)
import Data.Default

main = scotty 3000 $ do
    --log requests to console
    logger <- liftIO $ mkRequestLogger def { outputFormat = Apache FromHeader }
    middleware logger

    get "/:word" $ do
        beam <- param "word"
        html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]

From the description, it also looks like Apache FromFallback will check the headers first, and use the socket IP address if no header is found.

Update

You can also just create the logger outside the scotty function:

main = do
    logger <- mkRequestLogger def { outputFormat = Apache FromHeader }
    scotty 3000 $ do
        middleware logger

        get "/:word" $ do
            beam <- param "word"
            html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]
Shaun the Sheep
  • 22,353
  • 1
  • 72
  • 100
  • Hi Luke. Your code worked perfectly back in 2014. But now, with the latest Stack snapshot, it no longer compiles. (It's complaining now that there is no `MonadIO` instance for the stuff that `mkRequestLogger` returns.) Do you have time to look at what changed in the meantime and how to get around it? I'd be happy to give you +50 bounty award for it. Thank you. – stackoverflowuser Mar 26 '16 at 12:03
  • Thanks, it works now! I've set the bounty and can award it to you in 24 hours. Another question in the meantime: Can you see why things stopped working? Did they just remove a `MonadIO` instance at some point? As an experienced Haskell programmer, can you imagine why they would do that in the first place? – stackoverflowuser Mar 26 '16 at 22:09
  • 1
    If you look at the changelog, you can see that the `MonadIO` instance [was removed from `ActionT`](https://github.com/scotty-web/scotty/commit/7e2960245c798a2eb7b9d58e270c11cbf7edb877). The commit log doesn't explain the motivation though, but I guess it allows for situations where you don't want all IO exceptions to be trapped within Scotty, which is what happened before. – Shaun the Sheep Mar 27 '16 at 14:43
  • 1
    Looks like it might be related to [this issue](https://github.com/scotty-web/scotty/issues/175). – Shaun the Sheep Mar 27 '16 at 14:49
  • Thanks! You'll get the bounty in 6 hours :) – stackoverflowuser Mar 27 '16 at 16:04