Skip to content

Commit 9a835b4

Browse files
Merge pull request #40 from robertmassaioli/issue/62-snap-server-0.10.0.0-release-notes
Issue 62: Wrote the first version of the snap-server-0.10.0.0 release notes.
2 parents 7fd81b5 + 04a668d commit 9a835b4

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
| title: Announcing: Snap Server v0.10.0.0
2+
| author: Robert Massaioli <robertmassaioli@gmail.com>
3+
| published: 2015-06-12T06:10:00+1000
4+
| updated: 2015-06-12T06:10:00+1000
5+
| summary: Release notes for Snap Server v0.10.0.0
6+
7+
The snap team is happy to announce the release of version 0.10.0.0 of snap-server.
8+
9+
## Changes
10+
11+
This release of snap-server only contains one major change from 0.9.5.0 and that is the addition of
12+
custom logging.
13+
14+
### Custom Access and Error logging for Snap Server
15+
16+
In this release of snap-server we include two new configuration options aimed at letting you control
17+
the logging format of snap-server.
18+
19+
Currently snap-server access logs appear in a format that resembles a common Apache httpd log format. For example,
20+
it should be familiar to see a log line like the following from your snap application:
21+
22+
127.0.0.1 - - [10/Jun/2015:14:12:55 +1000] "POST /rest/round-rooms HTTP/1.1" 200 - "http://localhost:8080/panel/hackathon-round-transition?project_id=10000&project_key=SP" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36"
23+
24+
And the error log is logged in a similar, but not quite the same, format and looks like:
25+
26+
[04/Dec/2014:11:11:57 +1100] Server.httpServe: START, binding to [http://0.0.0.0:8080/]
27+
28+
With the latest release of snap-server you are now free to define your own custom logging format! If
29+
you choose to not define you own custom format then the access and error logs will continue to
30+
appear in the same format.
31+
32+
### Custom Access Logging (a working example)
33+
34+
To create you own custom access and error logging formats snap-server provides two new configuration
35+
options setAccessLogHandler and setErrorLogHandler respectively. These methods will let you control
36+
how the access and error log lines are rendered. Lets run through a quick example with the
37+
setAccessLogHandler method. But first lets look at the types! The first type we will look at is:
38+
39+
setAccessLogHandler :: AccessLogHandler -> Config m a -> Config m a
40+
41+
This method accepts an AccessLogHandler and updates your snap-server configuration to use it. But
42+
what is an AccessLogHandler? An AccessLogHandler lets you get contextual information from the
43+
current request / response and output access log lines as a result and thus is defined as the
44+
following simple type alias:
45+
46+
type AccessLogHandler = Request -> Response -> IO ByteString
47+
48+
As you can see the AccessLogHandler is passed the Snap Request and Response so that you can log
49+
whatever you like in a context sensitive manner. Lets now show a working example of actually using
50+
these new types to log in JSON format using the [Aeson][1] library. First lets define a datatype that
51+
will represent the JSON data that should appear on each line of our log file:
52+
53+
-- import qualified Data.Text as T
54+
data AccessLogLine = AccessLogLine
55+
{ allEvent :: String
56+
, allTimestamp :: UTCTime
57+
, allHost :: T.Text
58+
, allMethod :: T.Text
59+
, allUrl :: T.Text
60+
, allHttpVersion :: T.Text
61+
, allStatus :: Int
62+
, allResponseContentLength :: Maybe Int64
63+
, allReferer :: Maybe T.Text
64+
, allUserAgent :: Maybe T.Text
65+
} deriving (Show, Generic)
66+
67+
As you can see this definition contains a lot of information about the request and response. We can
68+
now define a ToJSON instance for this data type so that we can encode it easily. We will use the
69+
derived Generic instance and a few helper methods to define the ToJSON instance:
70+
71+
instance ToJSON AccessLogLine where
72+
toJSON = genericToJSON defaultOptions
73+
{ fieldLabelModifier = stripFieldNamePrefix "all"
74+
}
75+
76+
stripFieldNamePrefix :: String -> String -> String
77+
stripFieldNamePrefix pre = lowerFirst . try (L.stripPrefix pre)
78+
79+
lowerFirst :: String -> String
80+
lowerFirst (x : xs) = C.toLower x : xs
81+
lowerFirst [] = []
82+
83+
Now it is a simple matter of defining the AccessLogHandler itself which will take the request and
84+
response, put the relevant data into an AccessLogLine and then return the encoded version of the
85+
AccessLogLine in JSON format:
86+
87+
-- import qualified Data.Text as T
88+
-- import qualified Data.Text.Encoding as T
89+
-- import qualified Snap.Core as SC
90+
-- import qualified Snap.Types.Headers as H
91+
accessLogHandler :: AccessLogHandler
92+
accessLogHandler req rsp = do
93+
let hdrs = SC.headers req
94+
let host = SC.rqRemoteAddr req
95+
let (v, v') = SC.rqVersion req
96+
let referer = head <$> H.lookup "referer" hdrs
97+
let userAgent = head <$> H.lookup "user-agent" hdrs
98+
99+
currentTime <- getCurrentTime
100+
return . L.toStrict . encode $ AccessLogLine
101+
{ allEvent = "log.access"
102+
, allTimestamp = currentTime
103+
, allHost = t host
104+
, allMethod = tshow . SC.rqMethod $ req
105+
, allUrl = t . SC.rqURI $ req
106+
, allHttpVersion = T.concat [ tshow v, ".", tshow v' ]
107+
, allStatus = SC.rspStatus rsp
108+
, allResponseContentLength = rspContentLength rsp
109+
, allReferer = t <$> referer
110+
, allUserAgent = t <$> userAgent
111+
}
112+
where
113+
tshow :: Show a => a -> T.Text
114+
tshow = T.pack . show
115+
t = T.decodeUtf8
116+
117+
As you can see there is nothing overly complicated going on inside our accessLogHandler but now we
118+
can use the following code to update our snap-server configuration:
119+
120+
setAccessLogHandler accessLogHandler
121+
122+
And now the access logs for our snap application running on snap-server are being output in JSON
123+
format! You are now free to reuse this code in your own applications or to define your own custom
124+
formats. Please let us know what formats you were able to define that were the most useful to you.
125+
126+
We hope that this change allows for better integration with third party tools or simply allows you to
127+
extract the information that you need from snap-server. Good luck and keep writing awesome web
128+
apps in snap!
129+
130+
[1]: http://hackage.haskell.org/package/aeson

0 commit comments

Comments
 (0)