├── docs ├── CNAME ├── reference │ ├── Rplot001.png │ ├── index.html │ ├── log_info.html │ ├── log_debug.html │ ├── log_fatal.html │ ├── log_trace.html │ ├── log_error.html │ └── log_warn.html ├── pkgdown.yml ├── sitemap.xml ├── link.svg ├── bootstrap-toc.css ├── docsearch.js ├── pkgdown.js ├── authors.html ├── bootstrap-toc.js ├── LICENSE-text.html ├── 404.html ├── news │ └── index.html ├── LICENSE.html ├── pkgdown.css ├── docsearch.css └── index.html ├── .github ├── .gitignore └── workflows │ ├── rspm-merge.yml │ ├── R-CMD-check.yaml │ └── rhub.yaml ├── _pkgdown.yml ├── LICENSE ├── .gitignore ├── tests ├── testthat.R └── testthat │ └── test-helpers.R ├── CRAN-RELEASE ├── .Rbuildignore ├── NAMESPACE ├── NEWS.md ├── rlog.Rproj ├── man ├── log_info.Rd ├── log_debug.Rd ├── log_fatal.Rd ├── log_trace.Rd ├── log_warn.Rd └── log_error.Rd ├── cran-comments.md ├── DESCRIPTION ├── R ├── log_msg.R └── helpers.R ├── LICENSE.md └── README.md /docs/CNAME: -------------------------------------------------------------------------------- 1 | rlog.sellorm.com -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://rlog.sellorm.com 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2021 2 | COPYRIGHT HOLDER: rlog authors 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(rlog) 3 | 4 | test_check("rlog") 5 | -------------------------------------------------------------------------------- /docs/reference/Rplot001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sellorm/rlog/HEAD/docs/reference/Rplot001.png -------------------------------------------------------------------------------- /CRAN-RELEASE: -------------------------------------------------------------------------------- 1 | This package was submitted to CRAN on 2021-02-22. 2 | Once it is accepted, delete this file and tag the release (commit 8888830). 3 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^rlog\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^_pkgdown\.yml$ 5 | ^docs$ 6 | ^pkgdown$ 7 | ^cran-comments\.md$ 8 | ^CRAN-RELEASE$ 9 | ^\.github$ 10 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(log_debug) 4 | export(log_error) 5 | export(log_fatal) 6 | export(log_info) 7 | export(log_trace) 8 | export(log_warn) 9 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 2.11.4 2 | pkgdown: 1.6.1 3 | pkgdown_sha: ~ 4 | articles: {} 5 | last_built: 2021-02-21T20:07Z 6 | urls: 7 | reference: https://rlog.sellorm.com/reference 8 | article: https://rlog.sellorm.com/articles 9 | 10 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # rlog (development version) 2 | 3 | * The "log_" functions ("log_error", "log_info", etc) now accepts any number of 4 | arguments via ... in the function call. 5 | 6 | # rlog 0.1.0 7 | 8 | * Prepare for CRAN submission 9 | 10 | # rlog 0.0.0.9000 11 | 12 | * Added a `NEWS.md` file to track changes to the package. 13 | -------------------------------------------------------------------------------- /rlog.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | LineEndingConversion: Posix 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /man/log_info.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{log_info} 4 | \alias{log_info} 5 | \title{Log an info message} 6 | \usage{ 7 | log_info(message, ...) 8 | } 9 | \arguments{ 10 | \item{message}{your message to log} 11 | 12 | \item{...}{more elements of the message, to be concatenated with the message} 13 | } 14 | \value{ 15 | invisibly returns TRUE/FALSE 16 | } 17 | \description{ 18 | Log messages will only be emitted if the log priority matches or is higher 19 | than the priority of your message 20 | } 21 | \examples{ 22 | \dontrun{ 23 | log_info("This is an info message") 24 | Sys.setenv("LOG_LEVEL" = "TRACE") 25 | log_info("This is an info message") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /man/log_debug.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{log_debug} 4 | \alias{log_debug} 5 | \title{Log a debug message} 6 | \usage{ 7 | log_debug(message, ...) 8 | } 9 | \arguments{ 10 | \item{message}{your message to log} 11 | 12 | \item{...}{more elements of the message, to be concatenated with the message} 13 | } 14 | \value{ 15 | invisibly returns TRUE/FALSE 16 | } 17 | \description{ 18 | Log messages will only be emitted if the log priority matches or is higher 19 | than the priority of your message 20 | } 21 | \examples{ 22 | \dontrun{ 23 | log_debug("This is a debug message") 24 | Sys.setenv("LOG_LEVEL" = "TRACE") 25 | log_debug("This is a debug message") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /man/log_fatal.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{log_fatal} 4 | \alias{log_fatal} 5 | \title{Log a fatal message} 6 | \usage{ 7 | log_fatal(message, ...) 8 | } 9 | \arguments{ 10 | \item{message}{your message to log} 11 | 12 | \item{...}{more elements of the message, to be concatenated with the message} 13 | } 14 | \value{ 15 | invisibly returns TRUE/FALSE 16 | } 17 | \description{ 18 | Log messages will only be emitted if the log priority matches or is higher 19 | than the priority of your message 20 | } 21 | \examples{ 22 | \dontrun{ 23 | log_fatal("This is a fatal message") 24 | Sys.setenv("LOG_LEVEL" = "TRACE") 25 | log_fatal("This is a fatal message") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /man/log_trace.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{log_trace} 4 | \alias{log_trace} 5 | \title{Log a trace message} 6 | \usage{ 7 | log_trace(message, ...) 8 | } 9 | \arguments{ 10 | \item{message}{your message to log} 11 | 12 | \item{...}{more elements of the message, to be concatenated with the message} 13 | } 14 | \value{ 15 | invisibly returns TRUE/FALSE 16 | } 17 | \description{ 18 | Log messages will only be emitted if the log priority matches or is higher 19 | than the priority of your message 20 | } 21 | \examples{ 22 | \dontrun{ 23 | log_trace("This is a trace message") 24 | Sys.setenv("LOG_LEVEL" = "TRACE") 25 | log_trace("This is a trace message") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /man/log_warn.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{log_warn} 4 | \alias{log_warn} 5 | \title{Log a warning message} 6 | \usage{ 7 | log_warn(message, ...) 8 | } 9 | \arguments{ 10 | \item{message}{your message to log} 11 | 12 | \item{...}{more elements of the message, to be concatenated with the message} 13 | } 14 | \value{ 15 | invisibly returns TRUE/FALSE 16 | } 17 | \description{ 18 | Log messages will only be emitted if the log priority matches or is higher 19 | than the priority of your message 20 | } 21 | \examples{ 22 | \dontrun{ 23 | log_warn("This is a warning message") 24 | Sys.setenv("LOG_LEVEL" = "TRACE") 25 | log_warn("This is a warning message") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /man/log_error.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{log_error} 4 | \alias{log_error} 5 | \title{Log an error message} 6 | \usage{ 7 | log_error(message, ...) 8 | } 9 | \arguments{ 10 | \item{message}{your message to log} 11 | 12 | \item{...}{more elements of the message, to be concatenated with the message} 13 | } 14 | \value{ 15 | invisibly returns TRUE/FALSE 16 | } 17 | \description{ 18 | Log messages will only be emitted if the log priority matches or is higher 19 | than the priority of your message 20 | } 21 | \examples{ 22 | \dontrun{ 23 | log_error("This is an error message") 24 | Sys.setenv("LOG_LEVEL" = "TRACE") 25 | log_error("This is an error message") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Resumbmission 2 | 3 | This is a resubmission to mitigate the previous note about the misspelling of 4 | the package name in the description. Per CRAN advice, this is now enclosed in 5 | single quotes and resumbitted for consideration. 6 | 7 | ## Original submission test environments 8 | * local R installation, MacOS 11.1, R 4.0.3 9 | * Fedora Linux, R-devel, clang, gfortran (R-hub) 10 | * Ubuntu Linux 20.04.1 LTS, R-release, GCC (R-hub) 11 | * Windows Server 2008 R2 SP1, R-devel, 32/64 bit (R-hub) 12 | * win-builder (devel) 13 | 14 | ## Original R CMD check results 15 | 16 | 0 errors | 0 warnings | 1 note 17 | 18 | The note relates to a possible misspelling, but it's of the package name, 'rlog'. 19 | 20 | * This is a new release. 21 | -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://rlog.sellorm.com/index.html 5 | 6 | 7 | https://rlog.sellorm.com/reference/log_debug.html 8 | 9 | 10 | https://rlog.sellorm.com/reference/log_error.html 11 | 12 | 13 | https://rlog.sellorm.com/reference/log_fatal.html 14 | 15 | 16 | https://rlog.sellorm.com/reference/log_info.html 17 | 18 | 19 | https://rlog.sellorm.com/reference/log_trace.html 20 | 21 | 22 | https://rlog.sellorm.com/reference/log_warn.html 23 | 24 | 25 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: rlog 2 | Title: A Simple, Opinionated Logging Utility 3 | Version: 0.1.0.9999 4 | Authors@R: 5 | person(given = "Mark", 6 | family = "Sellors", 7 | role = c("aut", "cre"), 8 | email = "rstats@5vcc.com") 9 | Description: A very lightweight package that writes out log messages in an opinionated way. 10 | Simpler and lighter than other logging packages, 'rlog' provides a compact feature set that 11 | focuses on getting the job done in a Unix-like way. 12 | URL: https://github.com/sellorm/rlog 13 | BugReports: https://github.com/sellorm/rlog/issues 14 | License: MIT + file LICENSE 15 | Encoding: UTF-8 16 | LazyData: true 17 | Roxygen: list(markdown = TRUE) 18 | RoxygenNote: 7.3.2 19 | Suggests: 20 | testthat (>= 3.0.0) 21 | Config/testthat/edition: 3 22 | -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/rspm-merge.yml: -------------------------------------------------------------------------------- 1 | name: rspm-merge 2 | 3 | on: 4 | workflow_run: 5 | types: 6 | - completed 7 | workflows: 8 | # List all required workflow names here. 9 | - 'R-CMD-check' 10 | 11 | jobs: 12 | rspm-merge: 13 | name: rspm-merge 14 | runs-on: ubuntu-latest 15 | env: 16 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 17 | R_KEEP_PKG_SOURCE: yes 18 | 19 | steps: 20 | - uses: actions/checkout@v2 21 | - # It is often a desired behavior to merge only when a workflow execution 22 | # succeeds. This can be changed as needed. 23 | if: ${{ github.event.workflow_run.conclusion == 'success' }} 24 | name: Merge me! 25 | run: | 26 | git config --global user.email "nobody@example.com" 27 | git config --global user.name "GHA auto-commit" 28 | git checkout -B rspm 29 | git rebase main 30 | git push -u origin rspm 31 | shell: bash 32 | 33 | -------------------------------------------------------------------------------- /R/log_msg.R: -------------------------------------------------------------------------------- 1 | # Main log writing function 2 | log_msg <- function(msg_level = "INFO", message, ...) { 3 | level <- Sys.getenv("LOG_LEVEL", "INFO") 4 | levels <- list( 5 | "all" = 0, 6 | "trace" = 1, 7 | "debug" = 2, 8 | "info" = 3, 9 | "warn" = 4, 10 | "error" = 5, 11 | "fatal" = 6, 12 | "off" = 7 13 | ) 14 | if (is.null(levels[tolower(level)])) { 15 | stop("The LOG_LEVEL environment variable is incorrectly set") 16 | } 17 | if (as.integer(levels[tolower(level)]) <= as.integer(levels[tolower(msg_level)])) { 18 | log_text <- paste0(Sys.time(), 19 | " [", msg_level, "] ", 20 | paste(c(message, list(...)), sep = " ", collapse = " "), 21 | "\n", 22 | sep = "", 23 | collapse = "" 24 | ) 25 | if (as.integer(levels[tolower(msg_level)]) > 3) { 26 | cat(log_text, file = stderr()) 27 | } else { 28 | cat(log_text, file = stdout()) 29 | } 30 | invisible(TRUE) 31 | } else { 32 | invisible(FALSE) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2021 rlog authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/master/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: ubuntu-latest, r: 'release'} 22 | - {os: ubuntu-latest, r: 'oldrel-1'} 23 | 24 | env: 25 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 26 | R_KEEP_PKG_SOURCE: yes 27 | 28 | steps: 29 | - uses: actions/checkout@v2 30 | - uses: r-lib/actions/setup-r@v2 31 | with: 32 | r-version: ${{ matrix.config.r }} 33 | http-user-agent: ${{ matrix.config.http-user-agent }} 34 | use-public-rspm: true 35 | 36 | - uses: r-lib/actions/setup-r-dependencies@v2 37 | with: 38 | extra-packages: rcmdcheck 39 | 40 | - uses: r-lib/actions/check-r-package@v2 41 | 42 | - name: Show testthat output 43 | if: always() 44 | run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true 45 | shell: bash 46 | 47 | - name: Upload check results 48 | if: failure() 49 | uses: actions/upload-artifact@main 50 | with: 51 | name: ${{ runner.os }}-r${{ matrix.config.r }}-results 52 | path: check 53 | -------------------------------------------------------------------------------- /tests/testthat/test-helpers.R: -------------------------------------------------------------------------------- 1 | test_that("basic functionality is working", { 2 | expect_true(log_info("info")) 3 | expect_false(log_trace("trace")) 4 | expect_output(log_info("INFO")) 5 | expect_silent(log_trace("TRACE")) 6 | }) 7 | 8 | test_that("default functionality is OK", { 9 | Sys.unsetenv("LOG_LEVEL") 10 | expect_true(log_fatal("FATAL")) 11 | expect_true(log_error("ERROR")) 12 | expect_true(log_warn("WARN")) 13 | expect_output(log_info("INFO")) 14 | expect_silent(log_debug("DEBUG")) 15 | expect_silent(log_trace("TRACE")) 16 | }) 17 | 18 | test_that("default functionality is OK", { 19 | Sys.setenv("LOG_LEVEL" = "TRACE") 20 | expect_true(log_fatal("FATAL")) 21 | expect_true(log_error("ERROR")) 22 | expect_true(log_warn("WARN")) 23 | expect_output(log_info("INFO")) 24 | expect_output(log_debug("DEBUG")) 25 | expect_output(log_trace("TRACE")) 26 | }) 27 | 28 | test_that("output is going going to the correct stdout/stderr", { 29 | expect_match(capture.output(log_warn("warn"), type = "message"), "warn$") 30 | expect_match(capture.output(log_error("error"), type = "message"), "error$") 31 | expect_match(capture.output(log_fatal("fatal"), type = "message"), "fatal$") 32 | }) 33 | 34 | test_that("multi-part messages render as expected", { 35 | test_var1 <- "hats" 36 | test_var2 <- "shoes" 37 | test_var3 <- c("trilby", "porkpie", "fez") 38 | expect_output(log_info("my message", test_var1, test_var2, "end")) 39 | expect_match(capture_output(log_info("my message", test_var1, test_var2, "end")), "my message hats shoes end$") 40 | expect_match(capture_output(log_info("my message", test_var3)), 'my message c[(]\"trilby\", \"porkpie\", \"fez\"[)]$') 41 | }) 42 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | 6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ 7 | 8 | /* All levels of nav */ 9 | nav[data-toggle='toc'] .nav > li > a { 10 | display: block; 11 | padding: 4px 20px; 12 | font-size: 13px; 13 | font-weight: 500; 14 | color: #767676; 15 | } 16 | nav[data-toggle='toc'] .nav > li > a:hover, 17 | nav[data-toggle='toc'] .nav > li > a:focus { 18 | padding-left: 19px; 19 | color: #563d7c; 20 | text-decoration: none; 21 | background-color: transparent; 22 | border-left: 1px solid #563d7c; 23 | } 24 | nav[data-toggle='toc'] .nav > .active > a, 25 | nav[data-toggle='toc'] .nav > .active:hover > a, 26 | nav[data-toggle='toc'] .nav > .active:focus > a { 27 | padding-left: 18px; 28 | font-weight: bold; 29 | color: #563d7c; 30 | background-color: transparent; 31 | border-left: 2px solid #563d7c; 32 | } 33 | 34 | /* Nav: second level (shown on .active) */ 35 | nav[data-toggle='toc'] .nav .nav { 36 | display: none; /* Hide by default, but at >768px, show it */ 37 | padding-bottom: 10px; 38 | } 39 | nav[data-toggle='toc'] .nav .nav > li > a { 40 | padding-top: 1px; 41 | padding-bottom: 1px; 42 | padding-left: 30px; 43 | font-size: 12px; 44 | font-weight: normal; 45 | } 46 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 47 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 48 | padding-left: 29px; 49 | } 50 | nav[data-toggle='toc'] .nav .nav > .active > a, 51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 53 | padding-left: 28px; 54 | font-weight: 500; 55 | } 56 | 57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ 58 | nav[data-toggle='toc'] .nav > .active > ul { 59 | display: block; 60 | } 61 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /.github/workflows/rhub.yaml: -------------------------------------------------------------------------------- 1 | # R-hub's generic GitHub Actions workflow file. It's canonical location is at 2 | # https://github.com/r-hub/actions/blob/v1/workflows/rhub.yaml 3 | # You can update this file to a newer version using the rhub2 package: 4 | # 5 | # rhub::rhub_setup() 6 | # 7 | # It is unlikely that you need to modify this file manually. 8 | 9 | name: R-hub 10 | run-name: "${{ github.event.inputs.id }}: ${{ github.event.inputs.name || format('Manually run by {0}', github.triggering_actor) }}" 11 | 12 | on: 13 | workflow_dispatch: 14 | inputs: 15 | config: 16 | description: 'A comma separated list of R-hub platforms to use.' 17 | type: string 18 | default: 'linux,windows,macos' 19 | name: 20 | description: 'Run name. You can leave this empty now.' 21 | type: string 22 | id: 23 | description: 'Unique ID. You can leave this empty now.' 24 | type: string 25 | 26 | jobs: 27 | 28 | setup: 29 | runs-on: ubuntu-latest 30 | outputs: 31 | containers: ${{ steps.rhub-setup.outputs.containers }} 32 | platforms: ${{ steps.rhub-setup.outputs.platforms }} 33 | 34 | steps: 35 | # NO NEED TO CHECKOUT HERE 36 | - uses: r-hub/actions/setup@v1 37 | with: 38 | config: ${{ github.event.inputs.config }} 39 | id: rhub-setup 40 | 41 | linux-containers: 42 | needs: setup 43 | if: ${{ needs.setup.outputs.containers != '[]' }} 44 | runs-on: ubuntu-latest 45 | name: ${{ matrix.config.label }} 46 | strategy: 47 | fail-fast: false 48 | matrix: 49 | config: ${{ fromJson(needs.setup.outputs.containers) }} 50 | container: 51 | image: ${{ matrix.config.container }} 52 | 53 | steps: 54 | - uses: r-hub/actions/checkout@v1 55 | - uses: r-hub/actions/platform-info@v1 56 | with: 57 | token: ${{ secrets.RHUB_TOKEN }} 58 | job-config: ${{ matrix.config.job-config }} 59 | - uses: r-hub/actions/setup-deps@v1 60 | with: 61 | token: ${{ secrets.RHUB_TOKEN }} 62 | job-config: ${{ matrix.config.job-config }} 63 | - uses: r-hub/actions/run-check@v1 64 | with: 65 | token: ${{ secrets.RHUB_TOKEN }} 66 | job-config: ${{ matrix.config.job-config }} 67 | 68 | other-platforms: 69 | needs: setup 70 | if: ${{ needs.setup.outputs.platforms != '[]' }} 71 | runs-on: ${{ matrix.config.os }} 72 | name: ${{ matrix.config.label }} 73 | strategy: 74 | fail-fast: false 75 | matrix: 76 | config: ${{ fromJson(needs.setup.outputs.platforms) }} 77 | 78 | steps: 79 | - uses: r-hub/actions/checkout@v1 80 | - uses: r-hub/actions/setup-r@v1 81 | with: 82 | job-config: ${{ matrix.config.job-config }} 83 | token: ${{ secrets.RHUB_TOKEN }} 84 | - uses: r-hub/actions/platform-info@v1 85 | with: 86 | token: ${{ secrets.RHUB_TOKEN }} 87 | job-config: ${{ matrix.config.job-config }} 88 | - uses: r-hub/actions/setup-deps@v1 89 | with: 90 | job-config: ${{ matrix.config.job-config }} 91 | token: ${{ secrets.RHUB_TOKEN }} 92 | - uses: r-hub/actions/run-check@v1 93 | with: 94 | job-config: ${{ matrix.config.job-config }} 95 | token: ${{ secrets.RHUB_TOKEN }} 96 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('.navbar-fixed-top').headroom(); 6 | 7 | $('body').css('padding-top', $('.navbar').height() + 10); 8 | $(window).resize(function(){ 9 | $('body').css('padding-top', $('.navbar').height() + 10); 10 | }); 11 | 12 | $('[data-toggle="tooltip"]').tooltip(); 13 | 14 | var cur_path = paths(location.pathname); 15 | var links = $("#navbar ul li a"); 16 | var max_length = -1; 17 | var pos = -1; 18 | for (var i = 0; i < links.length; i++) { 19 | if (links[i].getAttribute("href") === "#") 20 | continue; 21 | // Ignore external links 22 | if (links[i].host !== location.host) 23 | continue; 24 | 25 | var nav_path = paths(links[i].pathname); 26 | 27 | var length = prefix_length(nav_path, cur_path); 28 | if (length > max_length) { 29 | max_length = length; 30 | pos = i; 31 | } 32 | } 33 | 34 | // Add class to parent
  • , and enclosing
  • if in dropdown 35 | if (pos >= 0) { 36 | var menu_anchor = $(links[pos]); 37 | menu_anchor.parent().addClass("active"); 38 | menu_anchor.closest("li.dropdown").addClass("active"); 39 | } 40 | }); 41 | 42 | function paths(pathname) { 43 | var pieces = pathname.split("/"); 44 | pieces.shift(); // always starts with / 45 | 46 | var end = pieces[pieces.length - 1]; 47 | if (end === "index.html" || end === "") 48 | pieces.pop(); 49 | return(pieces); 50 | } 51 | 52 | // Returns -1 if not found 53 | function prefix_length(needle, haystack) { 54 | if (needle.length > haystack.length) 55 | return(-1); 56 | 57 | // Special case for length-0 haystack, since for loop won't run 58 | if (haystack.length === 0) { 59 | return(needle.length === 0 ? 0 : -1); 60 | } 61 | 62 | for (var i = 0; i < haystack.length; i++) { 63 | if (needle[i] != haystack[i]) 64 | return(i); 65 | } 66 | 67 | return(haystack.length); 68 | } 69 | 70 | /* Clipboard --------------------------*/ 71 | 72 | function changeTooltipMessage(element, msg) { 73 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 74 | element.setAttribute('data-original-title', msg); 75 | $(element).tooltip('show'); 76 | element.setAttribute('data-original-title', tooltipOriginalTitle); 77 | } 78 | 79 | if(ClipboardJS.isSupported()) { 80 | $(document).ready(function() { 81 | var copyButton = ""; 82 | 83 | $(".examples, div.sourceCode").addClass("hasCopyButton"); 84 | 85 | // Insert copy buttons: 86 | $(copyButton).prependTo(".hasCopyButton"); 87 | 88 | // Initialize tooltips: 89 | $('.btn-copy-ex').tooltip({container: 'body'}); 90 | 91 | // Initialize clipboard: 92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 93 | text: function(trigger) { 94 | return trigger.parentNode.textContent; 95 | } 96 | }); 97 | 98 | clipboardBtnCopies.on('success', function(e) { 99 | changeTooltipMessage(e.trigger, 'Copied!'); 100 | e.clearSelection(); 101 | }); 102 | 103 | clipboardBtnCopies.on('error', function() { 104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 105 | }); 106 | }); 107 | } 108 | })(window.jQuery || window.$) 109 | -------------------------------------------------------------------------------- /R/helpers.R: -------------------------------------------------------------------------------- 1 | #' Log a trace message 2 | #' 3 | #' Log messages will only be emitted if the log priority matches or is higher 4 | #' than the priority of your message 5 | #' 6 | #' @param message your message to log 7 | #' @param ... more elements of the message, to be concatenated with the message 8 | #' 9 | #' @return invisibly returns TRUE/FALSE 10 | #' @examples 11 | #' \dontrun{ 12 | #' log_trace("This is a trace message") 13 | #' Sys.setenv("LOG_LEVEL" = "TRACE") 14 | #' log_trace("This is a trace message") 15 | #' } 16 | #' @export 17 | log_trace <- function(message, ...) { 18 | log_msg("TRACE", message, ...) 19 | } 20 | 21 | #' Log a debug message 22 | #' 23 | #' Log messages will only be emitted if the log priority matches or is higher 24 | #' than the priority of your message 25 | #' 26 | #' @param message your message to log 27 | #' @param ... more elements of the message, to be concatenated with the message 28 | #' 29 | #' @return invisibly returns TRUE/FALSE 30 | #' @examples 31 | #' \dontrun{ 32 | #' log_debug("This is a debug message") 33 | #' Sys.setenv("LOG_LEVEL" = "TRACE") 34 | #' log_debug("This is a debug message") 35 | #' } 36 | #' @export 37 | log_debug <- function(message, ...) { 38 | log_msg("DEBUG", message, ...) 39 | } 40 | 41 | #' Log an info message 42 | #' 43 | #' Log messages will only be emitted if the log priority matches or is higher 44 | #' than the priority of your message 45 | #' 46 | #' @param message your message to log 47 | #' @param ... more elements of the message, to be concatenated with the message 48 | #' 49 | #' @return invisibly returns TRUE/FALSE 50 | #' @examples 51 | #' \dontrun{ 52 | #' log_info("This is an info message") 53 | #' Sys.setenv("LOG_LEVEL" = "TRACE") 54 | #' log_info("This is an info message") 55 | #' } 56 | #' @export 57 | log_info <- function(message, ...) { 58 | log_msg("INFO", message, ...) 59 | } 60 | 61 | #' Log a warning message 62 | #' 63 | #' Log messages will only be emitted if the log priority matches or is higher 64 | #' than the priority of your message 65 | #' 66 | #' @param message your message to log 67 | #' @param ... more elements of the message, to be concatenated with the message 68 | #' 69 | #' @return invisibly returns TRUE/FALSE 70 | #' @examples 71 | #' \dontrun{ 72 | #' log_warn("This is a warning message") 73 | #' Sys.setenv("LOG_LEVEL" = "TRACE") 74 | #' log_warn("This is a warning message") 75 | #' } 76 | #' @export 77 | log_warn <- function(message, ...) { 78 | log_msg("WARN", message, ...) 79 | } 80 | 81 | #' Log an error message 82 | #' 83 | #' Log messages will only be emitted if the log priority matches or is higher 84 | #' than the priority of your message 85 | #' 86 | #' @param message your message to log 87 | #' @param ... more elements of the message, to be concatenated with the message 88 | #' 89 | #' @return invisibly returns TRUE/FALSE 90 | #' @examples 91 | #' \dontrun{ 92 | #' log_error("This is an error message") 93 | #' Sys.setenv("LOG_LEVEL" = "TRACE") 94 | #' log_error("This is an error message") 95 | #' } 96 | #' @export 97 | log_error <- function(message, ...) { 98 | log_msg("ERROR", message, ...) 99 | } 100 | 101 | 102 | #' Log a fatal message 103 | #' 104 | #' Log messages will only be emitted if the log priority matches or is higher 105 | #' than the priority of your message 106 | #' 107 | #' @param message your message to log 108 | #' @param ... more elements of the message, to be concatenated with the message 109 | #' 110 | #' @return invisibly returns TRUE/FALSE 111 | #' @examples 112 | #' \dontrun{ 113 | #' log_fatal("This is a fatal message") 114 | #' Sys.setenv("LOG_LEVEL" = "TRACE") 115 | #' log_fatal("This is a fatal message") 116 | #' } 117 | #' @export 118 | log_fatal <- function(message, ...) { 119 | log_msg("FATAL", message, ...) 120 | } 121 | -------------------------------------------------------------------------------- /docs/authors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Authors • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
    62 |
    63 | 105 | 106 | 107 | 108 |
    109 | 110 |
    111 |
    112 | 115 | 116 |
      117 |
    • 118 |

      Mark Sellors. Author, maintainer. 119 |

      120 |
    • 121 |
    122 | 123 |
    124 | 125 |
    126 | 127 | 128 | 129 |
    130 | 133 | 134 |
    135 |

    Site built with pkgdown 1.6.1.

    136 |
    137 | 138 |
    139 |
    140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | (function() { 6 | 'use strict'; 7 | 8 | window.Toc = { 9 | helpers: { 10 | // return all matching elements in the set, or their descendants 11 | findOrFilter: function($el, selector) { 12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ 13 | // http://stackoverflow.com/a/12731439/358804 14 | var $descendants = $el.find(selector); 15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); 16 | }, 17 | 18 | generateUniqueIdBase: function(el) { 19 | var text = $(el).text(); 20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); 21 | return anchor || el.tagName.toLowerCase(); 22 | }, 23 | 24 | generateUniqueId: function(el) { 25 | var anchorBase = this.generateUniqueIdBase(el); 26 | for (var i = 0; ; i++) { 27 | var anchor = anchorBase; 28 | if (i > 0) { 29 | // add suffix 30 | anchor += '-' + i; 31 | } 32 | // check if ID already exists 33 | if (!document.getElementById(anchor)) { 34 | return anchor; 35 | } 36 | } 37 | }, 38 | 39 | generateAnchor: function(el) { 40 | if (el.id) { 41 | return el.id; 42 | } else { 43 | var anchor = this.generateUniqueId(el); 44 | el.id = anchor; 45 | return anchor; 46 | } 47 | }, 48 | 49 | createNavList: function() { 50 | return $(''); 51 | }, 52 | 53 | createChildNavList: function($parent) { 54 | var $childList = this.createNavList(); 55 | $parent.append($childList); 56 | return $childList; 57 | }, 58 | 59 | generateNavEl: function(anchor, text) { 60 | var $a = $(''); 61 | $a.attr('href', '#' + anchor); 62 | $a.text(text); 63 | var $li = $('
  • '); 64 | $li.append($a); 65 | return $li; 66 | }, 67 | 68 | generateNavItem: function(headingEl) { 69 | var anchor = this.generateAnchor(headingEl); 70 | var $heading = $(headingEl); 71 | var text = $heading.data('toc-text') || $heading.text(); 72 | return this.generateNavEl(anchor, text); 73 | }, 74 | 75 | // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). 76 | getTopLevel: function($scope) { 77 | for (var i = 1; i <= 6; i++) { 78 | var $headings = this.findOrFilter($scope, 'h' + i); 79 | if ($headings.length > 1) { 80 | return i; 81 | } 82 | } 83 | 84 | return 1; 85 | }, 86 | 87 | // returns the elements for the top level, and the next below it 88 | getHeadings: function($scope, topLevel) { 89 | var topSelector = 'h' + topLevel; 90 | 91 | var secondaryLevel = topLevel + 1; 92 | var secondarySelector = 'h' + secondaryLevel; 93 | 94 | return this.findOrFilter($scope, topSelector + ',' + secondarySelector); 95 | }, 96 | 97 | getNavLevel: function(el) { 98 | return parseInt(el.tagName.charAt(1), 10); 99 | }, 100 | 101 | populateNav: function($topContext, topLevel, $headings) { 102 | var $context = $topContext; 103 | var $prevNav; 104 | 105 | var helpers = this; 106 | $headings.each(function(i, el) { 107 | var $newNav = helpers.generateNavItem(el); 108 | var navLevel = helpers.getNavLevel(el); 109 | 110 | // determine the proper $context 111 | if (navLevel === topLevel) { 112 | // use top level 113 | $context = $topContext; 114 | } else if ($prevNav && $context === $topContext) { 115 | // create a new level of the tree and switch to it 116 | $context = helpers.createChildNavList($prevNav); 117 | } // else use the current $context 118 | 119 | $context.append($newNav); 120 | 121 | $prevNav = $newNav; 122 | }); 123 | }, 124 | 125 | parseOps: function(arg) { 126 | var opts; 127 | if (arg.jquery) { 128 | opts = { 129 | $nav: arg 130 | }; 131 | } else { 132 | opts = arg; 133 | } 134 | opts.$scope = opts.$scope || $(document.body); 135 | return opts; 136 | } 137 | }, 138 | 139 | // accepts a jQuery object, or an options object 140 | init: function(opts) { 141 | opts = this.helpers.parseOps(opts); 142 | 143 | // ensure that the data attribute is in place for styling 144 | opts.$nav.attr('data-toggle', 'toc'); 145 | 146 | var $topContext = this.helpers.createChildNavList(opts.$nav); 147 | var topLevel = this.helpers.getTopLevel(opts.$scope); 148 | var $headings = this.helpers.getHeadings(opts.$scope, topLevel); 149 | this.helpers.populateNav($topContext, topLevel, $headings); 150 | } 151 | }; 152 | 153 | $(function() { 154 | $('nav[data-toggle="toc"]').each(function(i, el) { 155 | var $nav = $(el); 156 | Toc.init($nav); 157 | }); 158 | }); 159 | })(); 160 | -------------------------------------------------------------------------------- /docs/LICENSE-text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | License • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
    62 |
    63 | 105 | 106 | 107 | 108 |
    109 | 110 |
    111 |
    112 | 115 | 116 |
    YEAR: 2021
    117 | COPYRIGHT HOLDER: rlog authors
    118 | 
    119 | 120 |
    121 | 122 | 127 | 128 |
    129 | 130 | 131 | 132 |
    133 | 136 | 137 |
    138 |

    Site built with pkgdown 1.6.1.

    139 |
    140 | 141 |
    142 |
    143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Page not found (404) • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
    62 |
    63 | 105 | 106 | 107 | 108 |
    109 | 110 |
    111 |
    112 | 115 | 116 | Content not found. Please use links in the navbar. 117 | 118 |
    119 | 120 | 125 | 126 |
    127 | 128 | 129 | 130 |
    131 | 134 | 135 |
    136 |

    Site built with pkgdown 1.6.1.

    137 |
    138 | 139 |
    140 |
    141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rlog 2 | 3 | 4 | [![R-CMD-check](https://github.com/sellorm/rlog/workflows/R-CMD-check/badge.svg)](https://github.com/sellorm/rlog/actions) 5 | 6 | 7 | rlog is an opinionated, lightweight logging package for R. 8 | 9 | It relies on long standing Unix traditions, to write simple log messages in a flexible way. 10 | 11 | Log message output looks like this: 12 | 13 | ``` 14 | 2021-02-21 17:19:06 [INFO] This is my log message 15 | ``` 16 | 17 | ## Installation 18 | 19 | Install rlog from GitHub with the following: 20 | 21 | ``` r 22 | devtools::install_github("sellorm/rlog") 23 | ``` 24 | 25 | ## Does R _really_ need another logging package? 26 | 27 | We think so, yes! 28 | 29 | There are already loads of logging packages for R. Many are no longer maintained and of the remaining selection some are overly complex, making them less approachable for beginners. 30 | 31 | Since logging should be an essential part of any production application or pipeline I think it's important that as many people as possible are introduced to good logging practice. 32 | 33 | If rlog doesn't have enough features for you, I'd recommend the excellent "[logger](https://cran.r-project.org/package=logger)" instead. 34 | 35 | ## rlog philosophy 36 | 37 | The rlog philosophy is the [Unix philosophy](https://en.wikipedia.org/wiki/Unix_philosophy) and as such, we expect applications using rlog to be able to integrate with other enterprise software quickly and efficiently. 38 | 39 | rlog is simple by design and it relies on existing Unix/Linux norms to get the job done. 40 | 41 | * Log message format is intentionally not configurable 42 | * the log level can only be controlled by an environment variable 43 | * log messages are written to standard output and standard error 44 | 45 | ## Usage 46 | 47 | The best way to use rlog is to call the functions directly from within your applications. 48 | 49 | There is one function per log message level: 50 | 51 | ``` r 52 | rlog::log_fatal("my fatal message") 53 | rlog::log_error("my error message") 54 | rlog::log_warn("my warn message") 55 | rlog::log_info("my info message") 56 | rlog::log_debug("my debug message") 57 | rlog::log_trace("my trace message") 58 | ``` 59 | 60 | If you run this code as-is without setting a custom `LOG_LEVEL` with the environment variable, you'll get output like this: 61 | 62 | ``` 63 | 2021-02-21 17:19:06 [FATAL] fatal 64 | 2021-02-21 17:19:06 [ERROR] error 65 | 2021-02-21 17:19:06 [WARN] warn 66 | 2021-02-21 17:19:06 [INFO] info 67 | ``` 68 | 69 | The "DEBUG" and "TRACE" message won't be printed, since the default `LOG_LEVEL` is "INFO" and those message have lower priority. 70 | 71 | Play around with setting the `LOG_LEVEL` directly in R and seeing what messages are emitted: 72 | 73 | ``` r 74 | Sys.setenv("LOG_LEVEL" = "ERROR") 75 | rlog::log_fatal("my fatal message") 76 | rlog::log_error("my error message") 77 | rlog::log_warn("my warn message") 78 | rlog::log_info("my info message") 79 | rlog::log_debug("my debug message") 80 | rlog::log_trace("my trace message") 81 | ``` 82 | 83 | Gives us this output: 84 | 85 | ``` 86 | 2021-02-21 17:19:06 [FATAL] fatal 87 | 2021-02-21 17:19:06 [ERROR] error 88 | ``` 89 | 90 | Remember though, the best way to set the environment variable is outside of the app. That way it's easier to change at run-time. 91 | 92 | So in your terminal you can do something like this before you run your script: 93 | 94 | ``` sh 95 | $ export LOG_LEVEL=TRACE 96 | $ ./my_script.R 97 | ``` 98 | 99 | Or you can even call your script with the appropriate value at run-time: 100 | 101 | ``` sh 102 | $ LOG_LEVEL=ERROR ./my_script.R 103 | ``` 104 | 105 | If you're using RStudio Connect users can set an environment variable called `LOG_LEVEL` in the "Vars" tab of their apps control panel. 106 | 107 | ## Setting the log level 108 | 109 | rlog relies on an environment variable called `LOG_LEVEL` to control which log messages are emitted. 110 | 111 | If it's not set, it will default to "INFO". 112 | 113 | The available levels -- in decreasing order of severity -- are as follows: 114 | 115 | * fatal 116 | * error 117 | * warn 118 | * info 119 | * debug 120 | * trace 121 | 122 | When the `LOG_LEVEL` environment variable is set to "INFO", only messages at that level and above will be emitted. 123 | 124 | Another example: 125 | 126 | * fatal 127 | * error 128 | * warn 129 | * info 130 | * debug <= If we set the log level here only messages of debug and above will be emitted. 131 | * trace 132 | 133 | This is a really powerful way of only including the messages you want to see in the log files at any given time. For example, you may choose to set the `LOG_LEVEL` to "TRACE" while developing your application or if it runs into a problem in production, but you might choose to run the application with a `LOG_LEVEL` of "ERROR" under normal circumstances. 134 | 135 | 136 | ## I want to write to a log file, not the console 137 | 138 | rlog outputs it log messages into the console in the same way that most Unix/Linux tools do. Ordinary messages go to "standard output" ([stdout](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout))) and errors go to "standard error" ([stderr](https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr))). 139 | 140 | This means they can be captured in the standard Unix/Linux way: 141 | 142 | ``` 143 | ./my_script.R > /path/to/file.log 2>&1 144 | ``` 145 | 146 | This command redirects stderr to stdout and drops it all into the `/path/to/file.log` file. 147 | 148 | You can also keep the "normal" and error outputs separate: 149 | 150 | ``` 151 | ./my_script.R > /path/to/file.log 2> /path/to/errors.log 152 | ``` 153 | 154 | Many enterprise software products, such as RStudio Connect will capture this output automatically and save it for you. 155 | -------------------------------------------------------------------------------- /docs/news/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Changelog • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
    62 |
    63 | 105 | 106 | 107 | 108 |
    109 | 110 |
    111 |
    112 | 116 | 117 |
    118 |

    119 | rlog 0.1.0

    120 |
      121 |
    • Prepare for CRAN submission
    • 122 |
    123 |
    124 |
    125 |

    126 | rlog 0.0.0.9000

    127 |
      128 |
    • Added a NEWS.md file to track changes to the package.
    • 129 |
    130 |
    131 |
    132 | 133 | 138 | 139 |
    140 | 141 | 142 |
    143 | 146 | 147 |
    148 |

    Site built with pkgdown 1.6.1.

    149 |
    150 | 151 |
    152 |
    153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /docs/LICENSE.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | MIT License • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
    62 |
    63 | 105 | 106 | 107 | 108 |
    109 | 110 |
    111 |
    112 | 115 | 116 |
    117 | 118 |

    Copyright (c) 2021 rlog authors

    119 |

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

    120 |

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    121 |

    THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

    122 |
    123 | 124 |
    125 | 126 | 131 | 132 |
    133 | 134 | 135 | 136 |
    137 | 140 | 141 |
    142 |

    Site built with pkgdown 1.6.1.

    143 |
    144 | 145 |
    146 |
    147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /docs/reference/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Function reference • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
    62 |
    63 | 105 | 106 | 107 | 108 |
    109 | 110 |
    111 |
    112 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 141 | 142 | 143 | 144 | 147 | 148 | 149 | 150 | 153 | 154 | 155 | 156 | 159 | 160 | 161 | 162 | 165 | 166 | 167 | 168 | 171 | 172 | 173 | 174 |
    127 |

    All functions

    128 |

    129 |
    139 |

    log_debug()

    140 |

    Log a debug message

    145 |

    log_error()

    146 |

    Log an error message

    151 |

    log_fatal()

    152 |

    Log a fatal message

    157 |

    log_info()

    158 |

    Log an info message

    163 |

    log_trace()

    164 |

    Log a trace message

    169 |

    log_warn()

    170 |

    Log a warning message

    175 |
    176 | 177 | 182 |
    183 | 184 | 185 |
    186 | 189 | 190 |
    191 |

    Site built with pkgdown 1.6.1.

    192 |
    193 | 194 |
    195 |
    196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /docs/reference/log_info.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Log an info message — log_info • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
    64 |
    65 | 107 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 119 | 120 |
    121 |

    Log messages will only be emitted if the log priority matches or is higher 122 | than the priority of your message

    123 |
    124 | 125 |
    log_info(message)
    126 | 127 |

    Arguments

    128 | 129 | 130 | 131 | 132 | 133 | 134 |
    message

    your message to log

    135 | 136 |

    Value

    137 | 138 |

    invisibly returns TRUE/FALSE

    139 | 140 |

    Examples

    141 |
    if (FALSE) { 142 | log_info("This is an info message") 143 | Sys.setenv("LOG_LEVEL" = "TRACE") 144 | log_info("This is an info message") 145 | } 146 |
    147 |
    148 | 153 |
    154 | 155 | 156 |
    157 | 160 | 161 |
    162 |

    Site built with pkgdown 1.6.1.

    163 |
    164 | 165 |
    166 |
    167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/reference/log_debug.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Log a debug message — log_debug • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
    64 |
    65 | 107 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 119 | 120 |
    121 |

    Log messages will only be emitted if the log priority matches or is higher 122 | than the priority of your message

    123 |
    124 | 125 |
    log_debug(message)
    126 | 127 |

    Arguments

    128 | 129 | 130 | 131 | 132 | 133 | 134 |
    message

    your message to log

    135 | 136 |

    Value

    137 | 138 |

    invisibly returns TRUE/FALSE

    139 | 140 |

    Examples

    141 |
    if (FALSE) { 142 | log_debug("This is a debug message") 143 | Sys.setenv("LOG_LEVEL" = "TRACE") 144 | log_debug("This is a debug message") 145 | } 146 |
    147 |
    148 | 153 |
    154 | 155 | 156 |
    157 | 160 | 161 |
    162 |

    Site built with pkgdown 1.6.1.

    163 |
    164 | 165 |
    166 |
    167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/reference/log_fatal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Log a fatal message — log_fatal • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
    64 |
    65 | 107 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 119 | 120 |
    121 |

    Log messages will only be emitted if the log priority matches or is higher 122 | than the priority of your message

    123 |
    124 | 125 |
    log_fatal(message)
    126 | 127 |

    Arguments

    128 | 129 | 130 | 131 | 132 | 133 | 134 |
    message

    your message to log

    135 | 136 |

    Value

    137 | 138 |

    invisibly returns TRUE/FALSE

    139 | 140 |

    Examples

    141 |
    if (FALSE) { 142 | log_fatal("This is a fatal message") 143 | Sys.setenv("LOG_LEVEL" = "TRACE") 144 | log_fatal("This is a fatal message") 145 | } 146 |
    147 |
    148 | 153 |
    154 | 155 | 156 |
    157 | 160 | 161 |
    162 |

    Site built with pkgdown 1.6.1.

    163 |
    164 | 165 |
    166 |
    167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/reference/log_trace.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Log a trace message — log_trace • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
    64 |
    65 | 107 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 119 | 120 |
    121 |

    Log messages will only be emitted if the log priority matches or is higher 122 | than the priority of your message

    123 |
    124 | 125 |
    log_trace(message)
    126 | 127 |

    Arguments

    128 | 129 | 130 | 131 | 132 | 133 | 134 |
    message

    your message to log

    135 | 136 |

    Value

    137 | 138 |

    invisibly returns TRUE/FALSE

    139 | 140 |

    Examples

    141 |
    if (FALSE) { 142 | log_trace("This is a trace message") 143 | Sys.setenv("LOG_LEVEL" = "TRACE") 144 | log_trace("This is a trace message") 145 | } 146 |
    147 |
    148 | 153 |
    154 | 155 | 156 |
    157 | 160 | 161 |
    162 |

    Site built with pkgdown 1.6.1.

    163 |
    164 | 165 |
    166 |
    167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/reference/log_error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Log an error message — log_error • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
    64 |
    65 | 107 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 119 | 120 |
    121 |

    Log messages will only be emitted if the log priority matches or is higher 122 | than the priority of your message

    123 |
    124 | 125 |
    log_error(message)
    126 | 127 |

    Arguments

    128 | 129 | 130 | 131 | 132 | 133 | 134 |
    message

    your message to log

    135 | 136 |

    Value

    137 | 138 |

    invisibly returns TRUE/FALSE

    139 | 140 |

    Examples

    141 |
    if (FALSE) { 142 | log_error("This is an error message") 143 | Sys.setenv("LOG_LEVEL" = "TRACE") 144 | log_error("This is an error message") 145 | } 146 |
    147 |
    148 | 153 |
    154 | 155 | 156 |
    157 | 160 | 161 |
    162 |

    Site built with pkgdown 1.6.1.

    163 |
    164 | 165 |
    166 |
    167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/reference/log_warn.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Log a warning message — log_warn • rlog 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
    64 |
    65 | 107 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 119 | 120 |
    121 |

    Log messages will only be emitted if the log priority matches or is higher 122 | than the priority of your message

    123 |
    124 | 125 |
    log_warn(message)
    126 | 127 |

    Arguments

    128 | 129 | 130 | 131 | 132 | 133 | 134 |
    message

    your message to log

    135 | 136 |

    Value

    137 | 138 |

    invisibly returns TRUE/FALSE

    139 | 140 |

    Examples

    141 |
    if (FALSE) { 142 | log_warn("This is a warning message") 143 | Sys.setenv("LOG_LEVEL" = "TRACE") 144 | log_warn("This is a warning message") 145 | } 146 |
    147 |
    148 | 153 |
    154 | 155 | 156 |
    157 | 160 | 161 |
    162 |

    Site built with pkgdown 1.6.1.

    163 |
    164 | 165 |
    166 |
    167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/pkgdown.css: -------------------------------------------------------------------------------- 1 | /* Sticky footer */ 2 | 3 | /** 4 | * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ 5 | * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css 6 | * 7 | * .Site -> body > .container 8 | * .Site-content -> body > .container .row 9 | * .footer -> footer 10 | * 11 | * Key idea seems to be to ensure that .container and __all its parents__ 12 | * have height set to 100% 13 | * 14 | */ 15 | 16 | html, body { 17 | height: 100%; 18 | } 19 | 20 | body { 21 | position: relative; 22 | } 23 | 24 | body > .container { 25 | display: flex; 26 | height: 100%; 27 | flex-direction: column; 28 | } 29 | 30 | body > .container .row { 31 | flex: 1 0 auto; 32 | } 33 | 34 | footer { 35 | margin-top: 45px; 36 | padding: 35px 0 36px; 37 | border-top: 1px solid #e5e5e5; 38 | color: #666; 39 | display: flex; 40 | flex-shrink: 0; 41 | } 42 | footer p { 43 | margin-bottom: 0; 44 | } 45 | footer div { 46 | flex: 1; 47 | } 48 | footer .pkgdown { 49 | text-align: right; 50 | } 51 | footer p { 52 | margin-bottom: 0; 53 | } 54 | 55 | img.icon { 56 | float: right; 57 | } 58 | 59 | img { 60 | max-width: 100%; 61 | } 62 | 63 | /* Fix bug in bootstrap (only seen in firefox) */ 64 | summary { 65 | display: list-item; 66 | } 67 | 68 | /* Typographic tweaking ---------------------------------*/ 69 | 70 | .contents .page-header { 71 | margin-top: calc(-60px + 1em); 72 | } 73 | 74 | dd { 75 | margin-left: 3em; 76 | } 77 | 78 | /* Section anchors ---------------------------------*/ 79 | 80 | a.anchor { 81 | margin-left: -30px; 82 | display:inline-block; 83 | width: 30px; 84 | height: 30px; 85 | visibility: hidden; 86 | 87 | background-image: url(./link.svg); 88 | background-repeat: no-repeat; 89 | background-size: 20px 20px; 90 | background-position: center center; 91 | } 92 | 93 | .hasAnchor:hover a.anchor { 94 | visibility: visible; 95 | } 96 | 97 | @media (max-width: 767px) { 98 | .hasAnchor:hover a.anchor { 99 | visibility: hidden; 100 | } 101 | } 102 | 103 | 104 | /* Fixes for fixed navbar --------------------------*/ 105 | 106 | .contents h1, .contents h2, .contents h3, .contents h4 { 107 | padding-top: 60px; 108 | margin-top: -40px; 109 | } 110 | 111 | /* Navbar submenu --------------------------*/ 112 | 113 | .dropdown-submenu { 114 | position: relative; 115 | } 116 | 117 | .dropdown-submenu>.dropdown-menu { 118 | top: 0; 119 | left: 100%; 120 | margin-top: -6px; 121 | margin-left: -1px; 122 | border-radius: 0 6px 6px 6px; 123 | } 124 | 125 | .dropdown-submenu:hover>.dropdown-menu { 126 | display: block; 127 | } 128 | 129 | .dropdown-submenu>a:after { 130 | display: block; 131 | content: " "; 132 | float: right; 133 | width: 0; 134 | height: 0; 135 | border-color: transparent; 136 | border-style: solid; 137 | border-width: 5px 0 5px 5px; 138 | border-left-color: #cccccc; 139 | margin-top: 5px; 140 | margin-right: -10px; 141 | } 142 | 143 | .dropdown-submenu:hover>a:after { 144 | border-left-color: #ffffff; 145 | } 146 | 147 | .dropdown-submenu.pull-left { 148 | float: none; 149 | } 150 | 151 | .dropdown-submenu.pull-left>.dropdown-menu { 152 | left: -100%; 153 | margin-left: 10px; 154 | border-radius: 6px 0 6px 6px; 155 | } 156 | 157 | /* Sidebar --------------------------*/ 158 | 159 | #pkgdown-sidebar { 160 | margin-top: 30px; 161 | position: -webkit-sticky; 162 | position: sticky; 163 | top: 70px; 164 | } 165 | 166 | #pkgdown-sidebar h2 { 167 | font-size: 1.5em; 168 | margin-top: 1em; 169 | } 170 | 171 | #pkgdown-sidebar h2:first-child { 172 | margin-top: 0; 173 | } 174 | 175 | #pkgdown-sidebar .list-unstyled li { 176 | margin-bottom: 0.5em; 177 | } 178 | 179 | /* bootstrap-toc tweaks ------------------------------------------------------*/ 180 | 181 | /* All levels of nav */ 182 | 183 | nav[data-toggle='toc'] .nav > li > a { 184 | padding: 4px 20px 4px 6px; 185 | font-size: 1.5rem; 186 | font-weight: 400; 187 | color: inherit; 188 | } 189 | 190 | nav[data-toggle='toc'] .nav > li > a:hover, 191 | nav[data-toggle='toc'] .nav > li > a:focus { 192 | padding-left: 5px; 193 | color: inherit; 194 | border-left: 1px solid #878787; 195 | } 196 | 197 | nav[data-toggle='toc'] .nav > .active > a, 198 | nav[data-toggle='toc'] .nav > .active:hover > a, 199 | nav[data-toggle='toc'] .nav > .active:focus > a { 200 | padding-left: 5px; 201 | font-size: 1.5rem; 202 | font-weight: 400; 203 | color: inherit; 204 | border-left: 2px solid #878787; 205 | } 206 | 207 | /* Nav: second level (shown on .active) */ 208 | 209 | nav[data-toggle='toc'] .nav .nav { 210 | display: none; /* Hide by default, but at >768px, show it */ 211 | padding-bottom: 10px; 212 | } 213 | 214 | nav[data-toggle='toc'] .nav .nav > li > a { 215 | padding-left: 16px; 216 | font-size: 1.35rem; 217 | } 218 | 219 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 220 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 221 | padding-left: 15px; 222 | } 223 | 224 | nav[data-toggle='toc'] .nav .nav > .active > a, 225 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 226 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 227 | padding-left: 15px; 228 | font-weight: 500; 229 | font-size: 1.35rem; 230 | } 231 | 232 | /* orcid ------------------------------------------------------------------- */ 233 | 234 | .orcid { 235 | font-size: 16px; 236 | color: #A6CE39; 237 | /* margins are required by official ORCID trademark and display guidelines */ 238 | margin-left:4px; 239 | margin-right:4px; 240 | vertical-align: middle; 241 | } 242 | 243 | /* Reference index & topics ----------------------------------------------- */ 244 | 245 | .ref-index th {font-weight: normal;} 246 | 247 | .ref-index td {vertical-align: top; min-width: 100px} 248 | .ref-index .icon {width: 40px;} 249 | .ref-index .alias {width: 40%;} 250 | .ref-index-icons .alias {width: calc(40% - 40px);} 251 | .ref-index .title {width: 60%;} 252 | 253 | .ref-arguments th {text-align: right; padding-right: 10px;} 254 | .ref-arguments th, .ref-arguments td {vertical-align: top; min-width: 100px} 255 | .ref-arguments .name {width: 20%;} 256 | .ref-arguments .desc {width: 80%;} 257 | 258 | /* Nice scrolling for wide elements --------------------------------------- */ 259 | 260 | table { 261 | display: block; 262 | overflow: auto; 263 | } 264 | 265 | /* Syntax highlighting ---------------------------------------------------- */ 266 | 267 | pre { 268 | word-wrap: normal; 269 | word-break: normal; 270 | border: 1px solid #eee; 271 | } 272 | 273 | pre, code { 274 | background-color: #f8f8f8; 275 | color: #333; 276 | } 277 | 278 | pre code { 279 | overflow: auto; 280 | word-wrap: normal; 281 | white-space: pre; 282 | } 283 | 284 | pre .img { 285 | margin: 5px 0; 286 | } 287 | 288 | pre .img img { 289 | background-color: #fff; 290 | display: block; 291 | height: auto; 292 | } 293 | 294 | code a, pre a { 295 | color: #375f84; 296 | } 297 | 298 | a.sourceLine:hover { 299 | text-decoration: none; 300 | } 301 | 302 | .fl {color: #1514b5;} 303 | .fu {color: #000000;} /* function */ 304 | .ch,.st {color: #036a07;} /* string */ 305 | .kw {color: #264D66;} /* keyword */ 306 | .co {color: #888888;} /* comment */ 307 | 308 | .message { color: black; font-weight: bolder;} 309 | .error { color: orange; font-weight: bolder;} 310 | .warning { color: #6A0366; font-weight: bolder;} 311 | 312 | /* Clipboard --------------------------*/ 313 | 314 | .hasCopyButton { 315 | position: relative; 316 | } 317 | 318 | .btn-copy-ex { 319 | position: absolute; 320 | right: 0; 321 | top: 0; 322 | visibility: hidden; 323 | } 324 | 325 | .hasCopyButton:hover button.btn-copy-ex { 326 | visibility: visible; 327 | } 328 | 329 | /* headroom.js ------------------------ */ 330 | 331 | .headroom { 332 | will-change: transform; 333 | transition: transform 200ms linear; 334 | } 335 | .headroom--pinned { 336 | transform: translateY(0%); 337 | } 338 | .headroom--unpinned { 339 | transform: translateY(-100%); 340 | } 341 | 342 | /* mark.js ----------------------------*/ 343 | 344 | mark { 345 | background-color: rgba(255, 255, 51, 0.5); 346 | border-bottom: 2px solid rgba(255, 153, 51, 0.3); 347 | padding: 1px; 348 | } 349 | 350 | /* vertical spacing after htmlwidgets */ 351 | .html-widget { 352 | margin-bottom: 10px; 353 | } 354 | 355 | /* fontawesome ------------------------ */ 356 | 357 | .fab { 358 | font-family: "Font Awesome 5 Brands" !important; 359 | } 360 | 361 | /* don't display links in code chunks when printing */ 362 | /* source: https://stackoverflow.com/a/10781533 */ 363 | @media print { 364 | code a:link:after, code a:visited:after { 365 | content: ""; 366 | } 367 | } 368 | -------------------------------------------------------------------------------- /docs/docsearch.css: -------------------------------------------------------------------------------- 1 | /* Docsearch -------------------------------------------------------------- */ 2 | /* 3 | Source: https://github.com/algolia/docsearch/ 4 | License: MIT 5 | */ 6 | 7 | .algolia-autocomplete { 8 | display: block; 9 | -webkit-box-flex: 1; 10 | -ms-flex: 1; 11 | flex: 1 12 | } 13 | 14 | .algolia-autocomplete .ds-dropdown-menu { 15 | width: 100%; 16 | min-width: none; 17 | max-width: none; 18 | padding: .75rem 0; 19 | background-color: #fff; 20 | background-clip: padding-box; 21 | border: 1px solid rgba(0, 0, 0, .1); 22 | box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .175); 23 | } 24 | 25 | @media (min-width:768px) { 26 | .algolia-autocomplete .ds-dropdown-menu { 27 | width: 175% 28 | } 29 | } 30 | 31 | .algolia-autocomplete .ds-dropdown-menu::before { 32 | display: none 33 | } 34 | 35 | .algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-] { 36 | padding: 0; 37 | background-color: rgb(255,255,255); 38 | border: 0; 39 | max-height: 80vh; 40 | } 41 | 42 | .algolia-autocomplete .ds-dropdown-menu .ds-suggestions { 43 | margin-top: 0 44 | } 45 | 46 | .algolia-autocomplete .algolia-docsearch-suggestion { 47 | padding: 0; 48 | overflow: visible 49 | } 50 | 51 | .algolia-autocomplete .algolia-docsearch-suggestion--category-header { 52 | padding: .125rem 1rem; 53 | margin-top: 0; 54 | font-size: 1.3em; 55 | font-weight: 500; 56 | color: #00008B; 57 | border-bottom: 0 58 | } 59 | 60 | .algolia-autocomplete .algolia-docsearch-suggestion--wrapper { 61 | float: none; 62 | padding-top: 0 63 | } 64 | 65 | .algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column { 66 | float: none; 67 | width: auto; 68 | padding: 0; 69 | text-align: left 70 | } 71 | 72 | .algolia-autocomplete .algolia-docsearch-suggestion--content { 73 | float: none; 74 | width: auto; 75 | padding: 0 76 | } 77 | 78 | .algolia-autocomplete .algolia-docsearch-suggestion--content::before { 79 | display: none 80 | } 81 | 82 | .algolia-autocomplete .ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header { 83 | padding-top: .75rem; 84 | margin-top: .75rem; 85 | border-top: 1px solid rgba(0, 0, 0, .1) 86 | } 87 | 88 | .algolia-autocomplete .ds-suggestion .algolia-docsearch-suggestion--subcategory-column { 89 | display: block; 90 | padding: .1rem 1rem; 91 | margin-bottom: 0.1; 92 | font-size: 1.0em; 93 | font-weight: 400 94 | /* display: none */ 95 | } 96 | 97 | .algolia-autocomplete .algolia-docsearch-suggestion--title { 98 | display: block; 99 | padding: .25rem 1rem; 100 | margin-bottom: 0; 101 | font-size: 0.9em; 102 | font-weight: 400 103 | } 104 | 105 | .algolia-autocomplete .algolia-docsearch-suggestion--text { 106 | padding: 0 1rem .5rem; 107 | margin-top: -.25rem; 108 | font-size: 0.8em; 109 | font-weight: 400; 110 | line-height: 1.25 111 | } 112 | 113 | .algolia-autocomplete .algolia-docsearch-footer { 114 | width: 110px; 115 | height: 20px; 116 | z-index: 3; 117 | margin-top: 10.66667px; 118 | float: right; 119 | font-size: 0; 120 | line-height: 0; 121 | } 122 | 123 | .algolia-autocomplete .algolia-docsearch-footer--logo { 124 | background-image: url("data:image/svg+xml;utf8,"); 125 | background-repeat: no-repeat; 126 | background-position: 50%; 127 | background-size: 100%; 128 | overflow: hidden; 129 | text-indent: -9000px; 130 | width: 100%; 131 | height: 100%; 132 | display: block; 133 | transform: translate(-8px); 134 | } 135 | 136 | .algolia-autocomplete .algolia-docsearch-suggestion--highlight { 137 | color: #FF8C00; 138 | background: rgba(232, 189, 54, 0.1) 139 | } 140 | 141 | 142 | .algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight { 143 | box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5) 144 | } 145 | 146 | .algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content { 147 | background-color: rgba(192, 192, 192, .15) 148 | } 149 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | A Simple, Opinionated Logging Utility • rlog 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 22 | 23 | 24 |
    25 |
    68 | 69 | 70 | 71 | 72 |
    73 |
    74 |
    75 | 77 |

    rlog is an opinionated, lightweight logging package for R.

    78 |

    It relies on long standing Unix traditions, to write simple log messages in a flexible way.

    79 |

    Log message output looks like this:

    80 |
    2021-02-21 17:19:06 [INFO] This is my log message
    81 |
    82 |

    83 | Installation

    84 |

    Install rlog from GitHub with the following:

    85 |
     86 | devtools::install_github("sellorm/rlog")
    87 |
    88 |
    89 |

    90 | Does R really need another logging package?

    91 |

    We think so, yes!

    92 |

    There are already loads of logging packages for R. Many are no longer maintained and of the remaining selection some are overly complex, making them less approachable for beginners.

    93 |

    Since logging should be an essential part of any production application or pipeline I think it’s important that as many people as possible are introduced to good logging practice.

    94 |

    If rlog doesn’t have enough features for you, I’d recommend the excellent “logger” instead.

    95 |
    96 |
    97 |

    98 | rlog philosophy

    99 |

    The rlog philosophy is the Unix philosophy and as such, we expect applications using rlog to be able to integrate with other enterprise software quickly and efficiently.

    100 |

    rlog is simple by design and it relies on existing Unix/Linux norms to get the job done.

    101 |
      102 |
    • Log message format is intentionally not configurable
    • 103 |
    • the log level can only be controlled by an environment variable
    • 104 |
    • log messages are written to standard output and standard error
    • 105 |
    106 |
    107 |
    108 |

    109 | Usage

    110 |

    The best way to use rlag is to call the functions directly from within your applications.

    111 |

    There is one function per log message level:

    112 |
    113 | rlog::log_fatal("my fatal message")
    114 | rlog::log_error("my error message")
    115 | rlog::log_warn("my warn message")
    116 | rlog::log_info("my info message")
    117 | rlog::log_debug("my debug message")
    118 | rlog::log_trace("my trace message")
    119 |

    If you run this code as-is without setting a custom LOG_LEVEL with the environment variable, you’ll get output like this:

    120 |
    2021-02-21 17:19:06 [FATAL] fatal
    121 | 2021-02-21 17:19:06 [ERROR] error
    122 | 2021-02-21 17:19:06 [WARN] warn
    123 | 2021-02-21 17:19:06 [INFO] info
    124 |

    The “DEBUG” and “TRACE” message won’t be printed, since the default LOG_LEVEL is “INFO” and those message have lower priority.

    125 |

    Play around with setting the LOG_LEVEL directly in R and seeing what messages are emitted:

    126 |
    127 | Sys.setenv("LOG_LEVEL" = "ERROR")
    128 | rlog::log_fatal("my fatal message")
    129 | rlog::log_error("my error message")
    130 | rlog::log_warn("my warn message")
    131 | rlog::log_info("my info message")
    132 | rlog::log_debug("my debug message")
    133 | rlog::log_trace("my trace message")
    134 |

    Gives us this output:

    135 |
    2021-02-21 17:19:06 [FATAL] fatal
    136 | 2021-02-21 17:19:06 [ERROR] error
    137 |

    Remember though, the best way to set the environment variable is outside of the app. That way it’s easier to change at run-time.

    138 |

    So in your terminal you can do something like this before you run your script:

    139 |
    $ export LOG_LEVEL=TRACE
    140 | $ ./my_script.R
    141 |

    Or you can even call your script with the appropriate value at run-time:

    142 |
    $ LOG_LEVEL=ERROR ./my_script.R
    143 |

    If you’re using RStudio Connect users can set an environment variable called LOG_LEVEL in the “Vars” tab of their apps control panel.

    144 |
    145 |
    146 |

    147 | Setting the log level

    148 |

    rlog relies on an environment variable called LOG_LEVEL to control which log messages are emitted.

    149 |

    If it’s not set, it will default to “INFO”.

    150 |

    The available levels – in decreasing order of severity – are as follows:

    151 |
      152 |
    • fatal
    • 153 |
    • error
    • 154 |
    • warn
    • 155 |
    • info
    • 156 |
    • debug
    • 157 |
    • trace
    • 158 |
    159 |

    When the LOG_LEVEL environment variable is set to “INFO”, only messages at that level and above will be emitted.

    160 |

    Another example:

    161 |
      162 |
    • fatal
    • 163 |
    • error
    • 164 |
    • warn
    • 165 |
    • info
    • 166 |
    • debug <= If we set the log level here only messages of debug and above will be emitted.
    • 167 |
    • trace
    • 168 |
    169 |

    This is a really powerful way of only including the messages you want to see in the log files at any given time. For example, you may choose to set the LOG_LEVEL to “TRACE” while developing your application or if it runs into a problem in production, but you might choose to run the application with a LOG_LEVEL of “ERROR” under normal circumstances.

    170 |
    171 |
    172 |

    173 | I want to write to a log file, not the console

    174 |

    rlog outputs it log messages into the console in the same way that most Unix/Linux tools do. Ordinary messages go to “standard output” (stdout) and errors go to “standard error” (stderr).

    175 |

    This means they can be captured in the standard Unix/Linux way:

    176 |
    ./my_script.R > /path/to/file.log 2>&1
    177 |

    This command redirects stderr to stdout and drops it all into the /path/to/file.log file.

    178 |

    You can also keep the “normal” and error outputs separate:

    179 |
    ./my_script.R > /path/to/file.log 2> /path/to/errors.log
    180 |

    Many enterprise software products, such as RStudio Connect will capture this output automatically and save it for you.

    181 |
    182 |
    183 |
    184 | 185 | 208 |
    209 | 210 | 211 | 220 |
    221 | 222 | 223 | 224 | 225 | 226 | 227 | --------------------------------------------------------------------------------