{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Concurrent (threadDelay)
import Control.Monad.IO.Class (liftIO)
import qualified Data.Binary.Builder as Builder
import qualified Data.ByteString.Lazy.Char8 as LBSC8
import Instana.SDK.SDK (InstanaContext)
import qualified Instana.SDK.SDK as InstanaSDK
import qualified Instana.Wai.Middleware.Entry as InstanaWaiMiddleware
import qualified Network.HTTP.Client as HTTP
import qualified Network.HTTP.Types as HTTPTypes
import qualified Network.Wai as Wai
import qualified Network.Wai.Handler.Warp as Warp
import System.Environment (lookupEnv)
import qualified System.Exit as Exit
import System.IO (Handle, stdout)
import System.Log.Formatter
import System.Log.Handler (setFormatter)
import System.Log.Handler.Simple (GenericHandler, fileHandler,
streamHandler)
import System.Log.Logger (Priority (..), rootLoggerName,
setHandlers, setLevel,
updateGlobalLogger)
import System.Log.Logger (infoM)
import qualified System.Posix.Process as Posix
import System.Posix.Types (CPid)
appLogger :: String
appLogger = "WaiWithMiddleware"
application :: InstanaContext -> HTTP.Manager -> CPid -> Wai.Application
application instana httpManager pid request respond = do
let
route = Wai.pathInfo request
method = Wai.requestMethod request
case (method, route) of
(_, []) ->
root respond
(_, ["ping"]) ->
ping respond pid
("GET", ["api"]) ->
apiUnderTest instana httpManager request respond
("POST", ["shutdown"]) ->
shutDown respond
_ ->
respond404 respond
root ::
(Wai.Response -> IO Wai.ResponseReceived)
-> IO Wai.ResponseReceived
root respond =
respondWithPlainText
respond
"Instana Haskell Trace SDK Integration Test Wai Dummy App"
ping ::
(Wai.Response -> IO Wai.ResponseReceived)
-> CPid
-> IO Wai.ResponseReceived
ping respond pid = do
respond $
Wai.responseLBS HTTPTypes.status200 [] $ LBSC8.pack $ show pid
apiUnderTest ::
InstanaContext
-> HTTP.Manager
-> Wai.Request
-> (Wai.Response -> IO Wai.ResponseReceived)
-> IO Wai.ResponseReceived
apiUnderTest instana httpManager _ respond = do
requestOut <-
HTTP.parseUrlThrow $
"http://127.0.0.1:1302/?some=query¶meters=2&pass=secret"
_ <- InstanaSDK.withHttpExit
instana
requestOut
(\req -> do
_ <- HTTP.httpLbs req httpManager
threadDelay $ 1000 -- make sure there is a duration > 0
)
respond $
Wai.responseBuilder
HTTPTypes.status200
[("Content-Type", "application/json; charset=UTF-8")]
"{\"response\": \"ok\"}"
shutDown ::
(Wai.Response -> IO Wai.ResponseReceived)
-> IO Wai.ResponseReceived
shutDown respond = do
liftIO $ infoM appLogger $ "Wai/Warp app (/w middleware) shutdown requested"
_ <-liftIO $ Posix.exitImmediately Exit.ExitSuccess
respond $
Wai.responseBuilder HTTPTypes.status204 [] Builder.empty
respondWithPlainText ::
(Wai.Response -> IO Wai.ResponseReceived)
-> String
-> IO Wai.ResponseReceived
respondWithPlainText respond content =
respond $
Wai.responseLBS
HTTPTypes.status200
[("Content-Type", "text/plain")]
(LBSC8.pack content)
respond404 ::
(Wai.Response -> IO Wai.ResponseReceived)
-> IO Wai.ResponseReceived
respond404 respond =
respond $
Wai.responseLBS HTTPTypes.status404 [] "not found"
main :: IO ()
main = do
initLogging
httpManager <- initHttpManager
let
config = InstanaSDK.defaultConfig { InstanaSDK.agentPort = Just 1302 }
InstanaSDK.withConfiguredInstana config $ runApp httpManager
runApp :: HTTP.Manager -> InstanaContext -> IO ()
runApp httpManager instana = do
pid <- Posix.getProcessID
let
host = "127.0.0.1"
port = (1207 :: Int)
warpSettings =
((Warp.setPort 1207) . (Warp.setHost "127.0.0.1")) Warp.defaultSettings
infoM appLogger $
"Starting Wai/Warp app (/w middleware) at " ++ host ++ ":" ++ show port ++
" (PID: " ++ show pid ++ ")."
let
app = application instana httpManager pid
appWithMiddleware = InstanaWaiMiddleware.traceHttpEntries instana $ app
Warp.runSettings warpSettings $ appWithMiddleware
initLogging :: IO ()
initLogging = do
logLevelEnvVar <- lookupEnv "APP_LOG_LEVEL"
let
logLevel =
case logLevelEnvVar of
Just "DEBUG" -> DEBUG
_ -> INFO
updateGlobalLogger appLogger $ setLevel logLevel
appFileHandler <- fileHandler "wai-warp-app-with-middleware.log" logLevel
appStreamHandler <- streamHandler stdout logLevel
let
formattedAppFileHandler = withFormatter appFileHandler
formattedAppStreamHandler = withFormatter appStreamHandler
updateGlobalLogger appLogger $
setHandlers [ formattedAppFileHandler ]
updateGlobalLogger rootLoggerName $
setHandlers [ formattedAppStreamHandler ]
withFormatter :: GenericHandler Handle -> GenericHandler Handle
withFormatter handler = setFormatter handler formatter
where
timeFormat = "%F %H:%M:%S.%4q %z"
formatter = tfLogFormatter timeFormat "{$time $loggername $pid $prio} $msg"
initHttpManager :: IO HTTP.Manager
initHttpManager =
HTTP.newManager $
HTTP.defaultManagerSettings
{ HTTP.managerConnCount = 5
, HTTP.managerResponseTimeout = HTTP.responseTimeoutMicro $ 5000 * 1000
}