Skip to content

Commit

Permalink
LogParser solutions
Browse files Browse the repository at this point in the history
  • Loading branch information
lukestephenson-zendesk committed Oct 11, 2023
1 parent 8747b19 commit 159c49d
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 13 deletions.
53 changes: 44 additions & 9 deletions src/main/scala/introcourse/level07/LogParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ object LogParser {
* - Error with (severity: Int)
*/
enum LogLevel {
case TODO // enums must have as least one case, replace this when you are ready
case Info
case Warning
case Error(severity: Int)
}

/**
Expand All @@ -47,7 +49,8 @@ object LogParser {
type Timestamp = Int

enum LogMessage {
case TODO // enums must have as least one case, replace this when you are ready
case UnknownLog(message: String)
case KnownLog(logLevel: LogLevel, timestamp: Timestamp, message: String)
}

/**
Expand Down Expand Up @@ -77,15 +80,27 @@ object LogParser {
* Here is the beginning of one possible approach.
**/
def parseLog(str: String): LogMessage = {
def buildLogMessage(logLevel: LogLevel, timestampStr: String, message: String): Option[LogMessage] = {
parseIntOption(timestampStr).map(timestamp => LogMessage.KnownLog(logLevel, timestamp, message))
}

val fields = str.split(",").toList
val optLog: Option[LogMessage] = fields match {
case List("I", timestampStr, message) =>
parseIntOption(timestampStr).map(timestamp => ???)
case _ => ??? // Add more cases
buildLogMessage(LogLevel.Info, timestampStr, message)
case List("W", timestampStr, message) =>
buildLogMessage(LogLevel.Warning, timestampStr, message)
case List("E", severityStr, timestampStr, message) =>
parseIntOption(severityStr).flatMap(severity => buildLogMessage(LogLevel.Error(severity), timestampStr, message))
case _ => None
}

// What should we do if optLog is None?
???
// optLog match
// case Some(logMessage) => logMessage
// case None => LogMessage.UnknownLog(str)

optLog.getOrElse(LogMessage.UnknownLog(str))
}

/**
Expand All @@ -96,7 +111,9 @@ object LogParser {
* Hint: Convert an Array to a List with .toList
* What if we get an empty line from the fileContent?
*/
def parseLogFile(fileContent: String): List[LogMessage] = ???
def parseLogFile(fileContent: String): List[LogMessage] = {
fileContent.split("\n").toList.filterNot(_.isEmpty).map(parseLog)
}

/**
* Define a function that returns only logs that are errors over the given severity level.
Expand All @@ -108,7 +125,13 @@ object LogParser {
* scala> getErrorsOverSeverity(List(KnownLog(Error(2), 123, some error msg")), 2)
* > List()
**/
def getErrorsOverSeverity(logs: List[LogMessage], minimumSeverity: Int): List[LogMessage] = ???
def getErrorsOverSeverity(logs: List[LogMessage], minimumSeverity: Int): List[LogMessage] = {
logs.filter { message =>
message match
case LogMessage.KnownLog(LogLevel.Error(severity), _, _) if severity > minimumSeverity => true
case _ => false
}
}

/**
* Write a function to convert a `LogMessage` to a readable `String`.
Expand All @@ -124,7 +147,17 @@ object LogParser {
*
* Hint: Pattern match and use string interpolation
**/
def showLogMessage(log: LogMessage): String = ???
def showLogMessage(log: LogMessage): String = {
log match
case LogMessage.UnknownLog(message) => s"Unknown log: $message"
case LogMessage.KnownLog(logLevel, timestamp, message) =>
val severityStr = logLevel match
case LogLevel.Info => "Info"
case LogLevel.Warning => "Warning"
case LogLevel.Error(severity) => s"Error $severity"

s"$severityStr ($timestamp) $message"
}

/**
* Use `showLogMessage` on error logs with severity greater than the given `severity`.
Expand All @@ -134,7 +167,9 @@ object LogParser {
*
* Hint: Use `parseLogFile`, `getErrorsOverSeverity` and `showLogMessage`
**/
def showErrorsOverSeverity(fileContent: String, severity: Int): List[String] = ???
def showErrorsOverSeverity(fileContent: String, severity: Int): List[String] = {
getErrorsOverSeverity(parseLogFile(fileContent), severity).map(showLogMessage)
}

/**
* Now head over to `Main.scala` in the same package to complete the rest of the program.
Expand Down
6 changes: 4 additions & 2 deletions src/main/scala/introcourse/level07/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ object Main {
val fileContent: String = Source.fromFile(filepath).getLines().mkString("\n")

// Implement `printErrorsOverSeverity` and then call it from here
???
printErrorsOverSeverity(fileContent, 1)

case _ => println("""sbt "runMain introcourse.level07.Main src/main/resources/logfile.csv"""")
}
Expand All @@ -39,6 +39,8 @@ object Main {
* Hint: Use println to write to stdout
*/
@SuppressWarnings(Array("org.wartremover.warts.Any"))
private def printErrorsOverSeverity(logFile: String, severity: Int): Unit = ???
private def printErrorsOverSeverity(logFile: String, severity: Int): Unit = {
showErrorsOverSeverity(logFile, severity).foreach(println)
}

}
4 changes: 2 additions & 2 deletions src/test/scala/introcourse/level07/LogParserTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import org.scalactic.TypeCheckedTripleEquals
import org.scalatest.funspec.AnyFunSpec

class LogParserTest extends AnyFunSpec with TypeCheckedTripleEquals {
// TODO: Remove this import once you've defined the ADTs in LogParser
import Types.*
// // TODO: Remove this import once you've defined the ADTs in LogParser
// import Types.*

describe("parseIntOption") {
it("should return the parsed integer for a valid integer") {
Expand Down

0 comments on commit 159c49d

Please sign in to comment.