From 5744717f826673038f583a5bb7125ef0042a2f19 Mon Sep 17 00:00:00 2001 From: Greg Wilson Date: Sun, 21 Apr 2024 12:50:26 -0400 Subject: [PATCH] merge: logging framework placeholder --- README.md | 1 + _data/contrib.yml | 4 + _data/order.yml | 1 + _data/topic.yml | 5 + docs/index.html | 1 + docs/logger/index.html | 130 ++++++++++++++++++ .../iterations/0-minimal-logger/main.roc | 11 ++ .../iterations/1-append-to-file/main.roc | 34 +++++ .../1-append-to-file/main.sweet.roc | 35 +++++ docs/sitemap.xml | 9 +- logger/index.md | 3 +- 11 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 docs/logger/index.html create mode 100644 docs/logger/iterations/0-minimal-logger/main.roc create mode 100644 docs/logger/iterations/1-append-to-file/main.roc create mode 100644 docs/logger/iterations/1-append-to-file/main.sweet.roc diff --git a/README.md b/README.md index 7676334..1e53437 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ that most programmers have never encountered. | Stuart Hinson | stuarth | redis data store | redis | | Nathaniel Knight | nathanielknight | random number generation | prng | | Monica McGuigan | monmcguigan | JSON codec | json | +| Noel Rivas | noelrivasc | logging framework | logging | | Abhinav Sarkar | abhin4v | pretty printing | pretty | | Fabian Schmalzried | FabHof | binary data packing | binary | | Isaac Van Doren | isaacvando | compression | compress | diff --git a/_data/contrib.yml b/_data/contrib.yml index d551a81..a601f1a 100644 --- a/_data/contrib.yml +++ b/_data/contrib.yml @@ -46,6 +46,10 @@ personal: "Monica" github: "monmcguigan" +- family: "Rivas" + personal: "Noel" + github: "noelrivasc" + - family: "Sarkar" personal: "Abhinav" github: "abhin4v" diff --git a/_data/order.yml b/_data/order.yml index f7aaa79..dc448d9 100644 --- a/_data/order.yml +++ b/_data/order.yml @@ -4,6 +4,7 @@ chapters: - diff - json - pretty +- logger - prng - binary - ci diff --git a/_data/topic.yml b/_data/topic.yml index e03b939..b2f5c62 100644 --- a/_data/topic.yml +++ b/_data/topic.yml @@ -71,6 +71,11 @@ - slug: "license" title: "License" +- slug: "logger" + title: "A Logging Framework" + github: + - "noelrivasc" + - slug: "match" title: "Pattern Matching" github: diff --git a/docs/index.html b/docs/index.html index caec86e..b257a27 100644 --- a/docs/index.html +++ b/docs/index.html @@ -24,6 +24,7 @@

Software Design by Example in Roc

  • File Diffing
  • JSON Encoding and Decoding
  • Pretty Printing
  • +
  • A Logging Framework
  • Pseudorandom Number Generator
  • Binary Data Packing
  • Continuous Integration
  • diff --git a/docs/logger/index.html b/docs/logger/index.html new file mode 100644 index 0000000..e5cc10a --- /dev/null +++ b/docs/logger/index.html @@ -0,0 +1,130 @@ + + + + + + +Software Design by Example in Roc + + + + + + +
    +

    A Logging Framework

    +

    Written by Noel Rivas +

    + +

    This chapter goes through the building of a simple logging library with the following capabilities:

    + + + +

    Chapter structure

    + +

    The chapter follows a challenge and response pattern. The first iteration builds the simplest logger imaginable (just write to stdout) and each iteration improves on the previous one. After each implementation, its downsides are commented, and the next set of improvements are outlined.

    + +

    After the final implementation, a recap of the iterations, and the concepts that were explained in each of them, is offered.

    + +

    NOTE: On each of the iterations below, I’ll list some concepts that could be explained using the iteration code.

    + +

    The list is offered as a suggestion: whether we actually flesh out those concepts in this chapter or not will depend on the editorial decisions on chapter ordering and interdependence.

    + +

    0. Minimum viable logger

    + +

    An extremely simple, single-function “logger” that takes simple arguments (A message and a value) and outputs to Stdout.

    + +

    This iteration is only pertinent if the chapter introduces the concept of platform. It may be overkill in terms of paring down the first iteration.

    + +
    main =
    +    log "This is a value:" 42
    +    
    +log = \msg, val ->
    +    Stdout.line "$(msg): $(Inspect.toStr val)"
    +
    + +

    Concepts:

    + + + +

    1. Append to file

    + +

    At the end of this iteration, the logger:

    + + + +

    The idea behind its simplicity is to have the least amount of moving parts possible, so we can explore tasks, error handling, and the syntax around them in detail, without the burden of a larger program.

    + +

    I would like to present the code for this iteration with / without syntax sugar, and take steps to guide the reader to make the connection between type annotations in the documentation, the function calls without syntactic sugar, and the code with sugar.

    + +

    Concepts:

    + + + +

    2. A usable library

    + +

    This iteration is a small step from the previous one in terms of complexity of the logger. It mostly expands on the previous one as a reinforcement.

    + +

    An important step is that the logger becomes a module, and a more realistic use case is presented.

    + +

    At the end of this iteration, the logger:

    + + + +

    Concepts:

    + + + +

    3. Log level

    + +

    This iteration adds JSON encoding and log level configuration.

    + +

    NOTE: JSON encoding would depend on roc-json. If the library is too much, we can do something like rudimentary CSV without escaping or headers: just join a list with commas.

    + +

    Concepts:

    + + + +
    + + + + diff --git a/docs/logger/iterations/0-minimal-logger/main.roc b/docs/logger/iterations/0-minimal-logger/main.roc new file mode 100644 index 0000000..c55493e --- /dev/null +++ b/docs/logger/iterations/0-minimal-logger/main.roc @@ -0,0 +1,11 @@ +app "log-minimal" packages { + cli: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" + } + imports [cli.Stdout] + provides [ main ] to cli + +main = + log "This is a value:" 42 + +log = \msg, val -> + Stdout.line "$(msg): $(Inspect.toStr val)" \ No newline at end of file diff --git a/docs/logger/iterations/1-append-to-file/main.roc b/docs/logger/iterations/1-append-to-file/main.roc new file mode 100644 index 0000000..6e9a810 --- /dev/null +++ b/docs/logger/iterations/1-append-to-file/main.roc @@ -0,0 +1,34 @@ +app "log-append" packages { + cli: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" + } + imports [ + cli.Stdout, + cli.File, + cli.Task, + cli.Path, + cli.Utc, + ] + provides [ main ] to cli + +log = \msg, val -> + path = Path.fromStr "logFile" + Task.await Utc.now \now -> + millis = Utc.toMillisSinceEpoch now + seconds = Num.round (Num.toFrac millis / Num.toFrac 1000) + time = Num.toStr seconds + appendToFile path "$(time) $(msg): $(Inspect.toStr val)\n" + +# TODO: figure out type annotation, and its pertinence for this iteration +# appendToFile : Path, Str -> Task {} [FileReadErr Path.Path InternalFile.ReadErr, FileWriteErr Path.Path InternalFile.WriteErr] +appendToFile = \path, msg -> + newBytes = Str.toUtf8 msg + Task.await (File.readBytes path) \existingBytes -> + File.writeBytes path (List.concat newBytes existingBytes) + +main = + Task.onErr + (log "This is a value:" 42) + handleErr + +handleErr = \err -> + Stdout.line "We found an error: $(Inspect.toStr err)" \ No newline at end of file diff --git a/docs/logger/iterations/1-append-to-file/main.sweet.roc b/docs/logger/iterations/1-append-to-file/main.sweet.roc new file mode 100644 index 0000000..bb64038 --- /dev/null +++ b/docs/logger/iterations/1-append-to-file/main.sweet.roc @@ -0,0 +1,35 @@ +app "log-append" packages { + cli: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" + } + imports [ + cli.Stdout, + cli.File, + cli.Task, + cli.Path, + cli.Utc, + ] + provides [ main ] to cli + +log = \msg, val -> + path = Path.fromStr "logFile" + now <- Utc.now |> Task.await + millis = Utc.toMillisSinceEpoch now + seconds = Num.round (Num.toFrac millis / Num.toFrac 1000) + time = Num.toStr seconds + appendToFile path "$(time) $(msg): $(Inspect.toStr val)\n" + +# TODO: figure out type annotation, and its pertinence for this iteration +# appendToFile : Path, Str -> Task {} [FileReadErr Path.Path InternalFile.ReadErr, FileWriteErr Path.Path InternalFile.WriteErr] +appendToFile = \path, msg -> + newBytes = Str.toUtf8 msg + existingBytes <- File.readBytes path |> Task.await + File.writeBytes path (List.concat newBytes existingBytes) + +main = + log "This is a value:" + Task.onErr + (log "This is a value:" 42) + handleErr + +handleErr = \err -> + Stdout.line "We found an error: $(Inspect.toStr err)" diff --git a/docs/sitemap.xml b/docs/sitemap.xml index cfbd41e..4b987de 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -10,6 +10,9 @@ http://localhost:4000/book-of-examples/des/ +http://localhost:4000/book-of-examples/logger/ + + http://localhost:4000/book-of-examples/intro/ @@ -37,10 +40,10 @@ http://localhost:4000/book-of-examples/diff/ -http://localhost:4000/book-of-examples/parser/ +http://localhost:4000/book-of-examples/svg/ -http://localhost:4000/book-of-examples/svg/ +http://localhost:4000/book-of-examples/prng/ http://localhost:4000/book-of-examples/json/ @@ -70,7 +73,7 @@ http://localhost:4000/book-of-examples/ -http://localhost:4000/book-of-examples/prng/ +http://localhost:4000/book-of-examples/parser/ http://localhost:4000/book-of-examples/ftp/ diff --git a/logger/index.md b/logger/index.md index 3a08db3..59d88c9 100644 --- a/logger/index.md +++ b/logger/index.md @@ -1,4 +1,5 @@ -# Logging Library +--- +--- This chapter goes through the building of a simple logging library with the following capabilities: