A system has a transient problem. Logging is added to diagnose the problem which then becomes non-reproducible.
A user in a multi-user system performs an action known to produce an unexpected behavior. Tracing their execution through the log file is difficult because their log statements are interleaved with log statements from other users.
A user performs an action known to produce an unexpected behavior. Because the production system involves a cluster of servers, multiple log files must be downloaded and analyzed to find the activity of interest.
A user performs an action known to produce an unexpected behavior. The path of execution involves multiple server processes. Tracing the user's execution through the multiple systems is difficult because there is no reliable way to correlate the log statements across systems.
case class SimpleWriter[T](log: List[String], value: T) {
def map[B](f: T => B): SimpleWriter[B] =
SimpleWriter(log, f(value))
def flatMap[B](f: T => SimpleWriter[B]) = {
val nextWriter = f(value)
SimpleWriter(log ::: nextWriter.log, nextWriter.value)
}
}
def loggedAdder(a: Int, b: Int): SimpleWriter[Int] =
SimpleWriter(List(s"Added $a to $b"), a + b)
def loggedToString(o: Any): SimpleWriter[String] =
SimpleWriter(List(s"Converted $o to string"), o.toString)
def main(args: Array[String]) = {
val resultWithLog = for (
sum <- loggedAdder(5, 7);
converted <- loggedToString(sum)
) yield s"--> $converted <--"
resultWithLog.log.foreach(l => println(s"LOG: $l"))
println(s"Output is ${resultWithLog.value}")
}
LOG: Added 5 to 7
LOG: Converted 12 to string
Output is --> 12 <--
object SimpleLogger {
case class Entry(msg: String, timestamp: Long)
}
case class SimpleLogger[T](log: List[Entry], value: T) {
def map[B](f: T => B): SimpleLogger[B] =
SimpleLogger(log, f(value))
def flatMap[B](f: T => SimpleLogger[B]) = {
val nextWriter = f(value)
SimpleLogger(log ::: nextWriter.log, nextWriter.value)
}
}
A system has a transient problem. Turning logging on or off no longer affects program execution so the issue can be more easily analyzed.
A user in a multi-user system performs an action known to produce an unexpected behavior. It is easy to review their log entries because they are organized together along with context information for the operation.
INFO [127.0.0.1 - Anonymous] http://localhost:8080/api/board/8de53901-48b6-49b9-8a65-818b4a47d06e
[ 8 mSecs] select x2."id", x2."name", x2."terrain_set_id", x2."width", x2."height" from "board" x2 where x2."id" = ? -- Loaded 1 records
[ 5 mSecs] select x2."parent_id", x2."row", x2."column", x2."name", x2."capitol" from "board_city" x2 where x2."parent_id" = ? -- Loaded 3 records
[ 5 mSecs] select x2."parent_id", x2."row", x2."column", x2."terrain_type_index" from "board_terrain" x2 where x2."parent_id" = ? -- Loaded 24 records
A user performs an action known to produce an unexpected behavior. Because the application can deliver the server-side log entries back to the client, support staff has immediate access to the relevant information.
HTTP/1.1 200 OK
Date: Sat, 27 Feb 2016 19:54:14 GMT
Content-Type: application/json
Content-Length: 685
Service-Trace: select x2."id", x2."name", x2."terrain_set_id", x2."width", x2."height" from "board" x2 where x2."id" = ?; eventTime=0; duration=8; result=Loaded 1 records}
Service-Trace: select x2."parent_id", x2."row", x2."column", x2."name", x2."capitol" from "board_city" x2 where x2."parent_id" = ?; eventTime=14; duration=5; result=Loaded 3 records}
Service-Trace: select x2."parent_id", x2."row", x2."column", x2."terrain_type_index" from "board_terrain" x2 where x2."parent_id" = ?; eventTime=23; duration=5; result=Loaded 24 records}
A user performs an action known to produce an unexpected behavior. If we're really lucky and our whole world works this way, any server involved in the communication can aggregate all of the log entries for all involved servers.
This is where you come in!