├── .github └── workflows │ ├── ci.yml │ └── scripts │ ├── postinstall.js │ └── write-package-json.js ├── .gitignore ├── HISTORY.md ├── README.md ├── devbox.json ├── devbox.lock ├── dune-project ├── dune-workspace ├── example.png ├── examples ├── package.json ├── rescript.json └── src │ └── ReScript.res ├── lib ├── package.json ├── rescript.json └── src │ ├── Interface.res │ ├── Location.res │ └── loggers │ ├── Browser.res │ ├── Browser.resi │ ├── Edge.res │ ├── Edge.resi │ ├── Node.res │ ├── Node.resi │ ├── Universal.res │ └── Universal.resi ├── package.json ├── ppx ├── bin │ ├── Bin.ml │ └── dune └── lib │ ├── Lib.ml │ └── dune ├── rescript-logger-ppx.opam ├── windows.patch └── yarn.lock /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | tags: 9 | - 'v*' 10 | 11 | jobs: 12 | validate: 13 | name: Validate 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest] 18 | ocaml-version: [4.14.1] 19 | node-version: [16.x] 20 | 21 | steps: 22 | - name: Checkout repo 23 | uses: actions/checkout@v4 24 | 25 | - name: Setup Node ${{ matrix.node-version }} 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version: ${{ matrix.node-version }} 29 | 30 | - name: Print Yarn cache 31 | id: print-yarn-cache 32 | run: echo "yarn-cache=$(yarn cache dir)" >> $GITHUB_OUTPUT 33 | 34 | - name: Restore Yarn cache 35 | id: yarn-cache 36 | uses: actions/cache@v4 37 | with: 38 | path: ${{ steps.print-yarn-cache.outputs.yarn-cache }} 39 | key: ${{ matrix.os }}-yarn-${{ hashFiles('yarn.lock', '*/yarn.lock') }} 40 | 41 | - name: Install Yarn deps 42 | run: yarn install 43 | 44 | - name: Setup OCaml ${{ matrix.ocaml-version }} 45 | uses: ocaml/setup-ocaml@v2 46 | with: 47 | ocaml-compiler: ${{ matrix.ocaml-version }} 48 | 49 | - name: Install Opam deps 50 | run: opam install . --deps-only --with-test 51 | 52 | - name: Build PPX 53 | run: opam exec -- dune build 54 | 55 | - name: Build ReScript lib 56 | run: | 57 | cd lib 58 | yarn run build 59 | 60 | - name: Build ReScript examples 61 | run: | 62 | cd examples 63 | yarn run build 64 | 65 | build_macos: 66 | name: Build on ${{ matrix.os }} 67 | runs-on: ${{ matrix.os }} 68 | if: startsWith(github.ref, 'refs/tags/v') 69 | needs: 70 | - validate 71 | strategy: 72 | matrix: 73 | os: [macos-13, macos-14] 74 | ocaml-version: [4.14.1] 75 | node-version: [16.x] 76 | 77 | steps: 78 | - name: Checkout repo 79 | uses: actions/checkout@v4 80 | 81 | - name: Setup Node ${{ matrix.node-version }} 82 | uses: actions/setup-node@v4 83 | with: 84 | node-version: ${{ matrix.node-version }} 85 | 86 | - name: Print Yarn cache 87 | id: print-yarn-cache 88 | run: echo "yarn-cache=$(yarn cache dir)" >> $GITHUB_OUTPUT 89 | 90 | - name: Restore Yarn cache 91 | id: yarn-cache 92 | uses: actions/cache@v4 93 | with: 94 | path: ${{ steps.print-yarn-cache.outputs.yarn-cache }} 95 | key: ${{ matrix.os }}-yarn-${{ hashFiles('yarn.lock', '*/yarn.lock') }} 96 | 97 | - name: Install Yarn deps 98 | run: yarn install 99 | 100 | - name: Setup OCaml ${{ matrix.ocaml-version }} 101 | uses: ocaml/setup-ocaml@v2 102 | with: 103 | ocaml-compiler: ${{ matrix.ocaml-version }} 104 | 105 | - name: Install Opam deps 106 | run: opam install . --deps-only --with-test 107 | 108 | - name: Build PPX 109 | run: opam exec -- dune build 110 | 111 | - name: Build ReScript lib 112 | run: | 113 | cd lib 114 | yarn run build 115 | 116 | - name: Build ReScript examples 117 | run: | 118 | cd examples 119 | yarn run build 120 | 121 | - name: Upload artifacts 122 | uses: actions/upload-artifact@v4 123 | with: 124 | name: ${{ matrix.os }} 125 | path: _build/default/ppx/bin/bin.exe 126 | 127 | build_linux: 128 | name: Build on ${{ matrix.container-os }} 129 | runs-on: ${{ matrix.host-os }} 130 | if: startsWith(github.ref, 'refs/tags/v') 131 | needs: 132 | - validate 133 | strategy: 134 | matrix: 135 | host-os: [ubuntu-latest] 136 | container-os: [linux-alpine-3] 137 | ocaml-version: [4.14.1] 138 | node-version: [16.x] 139 | container: 140 | image: alex35mil/alpine-ocaml-opam-node-yarn:alpine-3.19-ocaml-4.14-node-16.20-yarn-1.22-o5gm 141 | 142 | steps: 143 | - name: Checkout repo 144 | uses: actions/checkout@v4 145 | 146 | - name: Print Yarn cache 147 | id: print-yarn-cache 148 | run: echo "yarn-cache=$(yarn cache dir)" >> $GITHUB_OUTPUT 149 | 150 | - name: Restore Yarn cache 151 | id: yarn-cache 152 | uses: actions/cache@v4 153 | with: 154 | path: ${{ steps.print-yarn-cache.outputs.yarn-cache }} 155 | key: ${{ matrix.container-os }}-yarn-${{ hashFiles('yarn.lock', '*/yarn.lock') }} 156 | 157 | - name: Install Yarn deps 158 | run: yarn install 159 | 160 | - name: Setup OCaml ${{ matrix.ocaml-version }} 161 | run: opam init -a --disable-sandboxing --compiler=${{ matrix.ocaml-version }} 162 | 163 | - name: Install Opam deps 164 | run: opam install . --deps-only --with-test 165 | 166 | - name: Build PPX 167 | run: opam exec -- dune build --profile static 168 | 169 | - name: Build ReScript lib 170 | run: | 171 | cd lib 172 | yarn run build 173 | 174 | - name: Build ReScript examples 175 | run: | 176 | cd examples 177 | yarn run build 178 | 179 | - name: Upload artifacts 180 | uses: actions/upload-artifact@v4 181 | with: 182 | name: ${{ matrix.container-os }} 183 | path: _build/default/ppx/bin/bin.exe 184 | 185 | build_windows: 186 | name: Build on ${{ matrix.os }} 187 | runs-on: ${{ matrix.os }} 188 | if: startsWith(github.ref, 'refs/tags/v') 189 | needs: 190 | - validate 191 | strategy: 192 | matrix: 193 | os: [windows-latest] 194 | ocaml-version: [4.14.1] 195 | node-version: [16.x] 196 | 197 | steps: 198 | - name: Checkout repo 199 | uses: actions/checkout@v4 200 | 201 | - name: Setup Node ${{ matrix.node-version }} 202 | uses: actions/setup-node@v4 203 | with: 204 | node-version: ${{ matrix.node-version }} 205 | 206 | - name: Print Yarn cache 207 | id: print-yarn-cache 208 | run: echo "::set-output name=yarn-cache::$(yarn cache dir)" # Using the old way as the new way doesn't work on windows 209 | 210 | - name: Restore Yarn cache 211 | id: yarn-cache 212 | uses: actions/cache@v4 213 | with: 214 | path: ${{ steps.print-yarn-cache.outputs.yarn-cache }} 215 | key: ${{ matrix.os }}-yarn-${{ hashFiles('yarn.lock', '*/yarn.lock') }} 216 | 217 | - name: Install Yarn deps 218 | run: yarn install 219 | 220 | - name: Apply Opam deps patch 221 | run: | 222 | $lastCommitterName = git log -1 --pretty=format:'%an' 223 | $lastCommitterEmail = git log -1 --pretty=format:'%ae' 224 | git config user.name "$lastCommitterName" 225 | git config user.email "$lastCommitterEmail" 226 | git apply windows.patch 227 | git add . 228 | git commit -m "Patch opam deps" 229 | 230 | - name: Setup OCaml ${{ matrix.ocaml-version }} 231 | uses: ocaml/setup-ocaml@v2 232 | with: 233 | ocaml-compiler: ${{ matrix.ocaml-version }} 234 | 235 | - name: Pin Opam deps 236 | run: | 237 | opam pin add dune https://github.com/ocaml/dune.git#7cbb0e7 # 3.11.1 238 | opam pin add ppxlib https://github.com/ocaml-ppx/ppxlib.git#f0496c9 # 0.30.0 239 | 240 | - name: Install Opam deps 241 | run: opam install . --deps-only --with-test 242 | 243 | - name: Build PPX 244 | run: opam exec -- dune build 245 | 246 | - name: Build ReScript lib 247 | run: | 248 | cd lib 249 | yarn run build 250 | 251 | - name: Build ReScript examples 252 | run: | 253 | cd examples 254 | yarn run build 255 | 256 | - name: Upload artifacts 257 | uses: actions/upload-artifact@v4 258 | with: 259 | name: ${{ matrix.os }} 260 | path: _build/default/ppx/bin/bin.exe 261 | 262 | release: 263 | needs: 264 | - build_macos 265 | - build_linux 266 | - build_windows 267 | name: Release 268 | runs-on: ubuntu-latest 269 | if: startsWith(github.ref, 'refs/tags/v') 270 | 271 | steps: 272 | - name: Checkout repo 273 | uses: actions/checkout@v4 274 | 275 | - name: Setup Node ${{ matrix.node-version }} 276 | uses: actions/setup-node@v4 277 | with: 278 | node-version: 16.x 279 | registry-url: "https://registry.npmjs.org" 280 | 281 | - name: Download macOS x86 artifacts 282 | uses: actions/download-artifact@v4 283 | with: 284 | name: macos-13 285 | path: _bin/darwin/intel 286 | 287 | - name: Download macOS ARM artifacts 288 | uses: actions/download-artifact@v4 289 | with: 290 | name: macos-14 291 | path: _bin/darwin/arm 292 | 293 | - name: Download Linux artifacts 294 | uses: actions/download-artifact@v4 295 | with: 296 | name: linux-alpine-3 297 | path: _bin/linux 298 | 299 | - name: Download Windows artifacts 300 | uses: actions/download-artifact@v4 301 | with: 302 | name: windows-latest 303 | path: _bin/windows 304 | 305 | - name: Move artifacts 306 | run: | 307 | mkdir -p _release/bin 308 | mv _bin/darwin/intel/bin.exe _release/bin/rescript-logger-ppx-darwin-x64.exe 309 | mv _bin/darwin/arm/bin.exe _release/bin/rescript-logger-ppx-darwin-arm64.exe 310 | mv _bin/linux/bin.exe _release/bin/rescript-logger-ppx-linux-x64.exe 311 | mv _bin/windows/bin.exe _release/bin/rescript-logger-ppx-win-x64.exe 312 | rm -rf _bin 313 | 314 | - name: Move lib files 315 | run: | 316 | mkdir -p _release/src 317 | cp README.md _release/README.md 318 | cp lib/rescript.json _release/rescript.json 319 | cp -a lib/src/. _release/src/ 320 | cp .github/workflows/scripts/postinstall.js _release/postinstall.js 321 | node .github/workflows/scripts/write-package-json.js 322 | 323 | - name: Upload release 324 | uses: actions/upload-artifact@v4 325 | with: 326 | name: release 327 | path: _release 328 | 329 | - name: Publish 330 | if: success() 331 | run: | 332 | cd _release 333 | npm publish 334 | env: 335 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 336 | -------------------------------------------------------------------------------- /.github/workflows/scripts/postinstall.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require("fs"); 4 | 5 | const PPX = "rescript-logger-ppx"; 6 | 7 | let arch = process.arch; 8 | let platform = process.platform; 9 | 10 | if (arch === "ia32") { 11 | arch = "x86"; 12 | } 13 | 14 | if (platform === "win32") { 15 | platform = "win"; 16 | } 17 | 18 | const filename = `bin/${PPX}-${platform}-${arch}.exe`; 19 | 20 | const supported = fs.existsSync(filename); 21 | 22 | if (!supported) { 23 | console.error(`${PPX} does not support this platform :(`); 24 | console.error(""); 25 | console.error(`${PPX} comes prepacked as built binaries to avoid large`); 26 | console.error("dependencies at build-time."); 27 | console.error(""); 28 | console.error(`If you want ${PPX} to support this platform natively,`); 29 | console.error("please open an issue at our repository, linked above. Please"); 30 | console.error(`specify that you are on the ${platform} platform,`); 31 | console.error(`on the ${arch} architecture.`); 32 | 33 | } 34 | 35 | if (!fs.existsSync("ppx.exe")) { 36 | copyFileSync(filename, "ppx.exe"); 37 | fs.chmodSync("ppx.exe", 0755); 38 | } 39 | 40 | if (!fs.existsSync("ppx")) { 41 | copyFileSync(filename, "ppx"); 42 | fs.chmodSync("ppx", 0755); 43 | } 44 | 45 | function copyFileSync(source, dest) { 46 | if (typeof fs.copyFileSync === "function") { 47 | fs.copyFileSync(source, dest); 48 | } else { 49 | fs.writeFileSync(dest, fs.readFileSync(source)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.github/workflows/scripts/write-package-json.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | 4 | const { 5 | name, 6 | version, 7 | description, 8 | author, 9 | license, 10 | repository, 11 | files, 12 | peerDependencies, 13 | keywords 14 | } = require("../../../package.json"); 15 | 16 | const packageJson = JSON.stringify( 17 | { 18 | name, 19 | version, 20 | description, 21 | author, 22 | license, 23 | repository, 24 | files, 25 | peerDependencies, 26 | keywords, 27 | scripts: { 28 | postinstall: "node ./postinstall.js" 29 | } 30 | }, 31 | null, 32 | 2 33 | ); 34 | 35 | fs.writeFileSync( 36 | path.join(__dirname, "..", "..", "..", "_release", "package.json"), 37 | packageJson, 38 | { encoding: "utf8" } 39 | ); 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .direnv/ 3 | .devbox/ 4 | .vscode/ 5 | .envrc 6 | .cache 7 | .merlin 8 | .bsb.lock 9 | *.res.js 10 | .DS_Store 11 | /_build 12 | /_release 13 | /lib/lib/ 14 | /examples/lib/ 15 | rescript-logger-ppx.install 16 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # History 2 | ## UNRELEASED 3 | 4 | ## 4.0.0 5 | - Update to ReScript 11. 6 | - Add `Edge` logger. 7 | - **[BREAKING]** Remove Linux `arm64` binary. 8 | 9 | ## 3.1.0 10 | - Add Linux `arm64` binary. 11 | 12 | ## 3.0.0 13 | - **[BREAKING]** Remove `filePath` from `Location.t`. 14 | - Upgrade to `rescript@10`. 15 | 16 | ## 2.2.0 17 | - Add universal logger (`ReScriptLogger.Universal`). Useful for apps with SSR. 18 | 19 | ## 2.1.0 20 | - Add native `arm64` support. 21 | 22 | ## 2.0.2 23 | - Remove `bs-platform` peer dependency. 24 | 25 | ## 2.0.1 26 | - Add support for M1 Macs through Rosetta [#28](https://github.com/shakacode/rescript-logger/pull/28). 27 | 28 | ## 2.0.0 29 | - Package renamed to `rescript-logger` and converted to `ReScript` syntax. 30 | - Default loggers namespaced and renamed: 31 | - `BrowserLogger` -> `ReScriptLogger.Browser` 32 | - `NodeLogger` -> `ReScriptLogger.Node` 33 | - Environment variables renamed: 34 | - `BS_LOG` -> `RES_LOG` 35 | - `BS_LOGGER` -> `RES_LOGGER` 36 | - Added environment variable `RES_LOG_ONLY`. It allows logging only from specific locations in code.
37 | E.g. `RES_LOG_ONLY=Module.Submodule.fn bsb ...`
38 | See [`Verbosity customization > Code location`](./README.md#code-location). 39 | - Each log entry produced by default loggers is prefixed with full location from where it's been called.
40 | E.g. `[Module.Submodule.fn] ...` 41 | - Logger interface changed (pay attention if you have custom loggers in your codebase): 42 | - Logger function `WithData` renamed to `1` 43 | - Logger function `WithData` renamed to `` 44 | - Each logger function receives `Location.t` record instead of a `__MODULE__` string. See [`Custom loggers`](./README.md#custom-loggers). 45 | 46 | ## 1.3.0 47 | - Add `Trace` level. 48 | - Ensure PPX binary is available on all platforms. 49 | 50 | ## 1.2.0 51 | - Make logging event polymorphic in `BrowserLogger` and `NodeLogger`. 52 | 53 | ## 1.1.0 54 | - Logging in libraries. 55 | 56 | ## 1.0.0 57 | - BuckleScript v7 support. 58 | - Make `warn` default log level for situations when `BS_LOG` env var doesn't exist. 59 | - Fix postinstall script for Windows. 60 | 61 | ## 0.1.1 62 | - Fix Windows build. 63 | 64 | ## 0.1.0 65 | - Prefix all log entries with value of a `__MODULE__` variable. 66 | - Update PPX setup. 67 | 68 | ## 0.0.9 69 | - Default logger renamed from `Console` to `BrowserLogger`. 70 | - Added `NodeLogger`. 71 | 72 | ## 0.0.8 73 | - Make `[@log]` annotation generic: it can be placed in front of any `switch` expression with constructors. 74 | - `[@log]` can accept optional namespace: `[@log "MyNamespace"]`. 75 | 76 | ## 0.0.7 77 | - Allow log statements inside annotated reducers. 78 | 79 | ## 0.0.6 80 | - Use default logger when `BS_LOGGER` is empty string. 81 | 82 | ## 0.0.5 83 | - Add `BS_LOGGER` environment variable. 84 | - Rename default logger from `Log` to `Console`. 85 | 86 | ## 0.0.4 87 | React logger. 88 | 89 | ## 0.0.3 90 | Lots of changes, hope nobody used it yet. 91 | 92 | ## 0.0.2 93 | Package renamed to `bs-log`. 94 | 95 | ## 0.0.1 96 | Initial release. 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rescript-logger 2 | 3 | [![npm version](https://img.shields.io/npm/v/rescript-logger.svg?style=flat-square)](https://www.npmjs.com/package/rescript-logger) 4 | [![license](https://img.shields.io/npm/l/rescript-logger.svg?style=flat-square)](https://www.npmjs.com/package/rescript-logger) 5 | 6 | Logging implementation for [ReScript](https://rescript-lang.org). 7 | 8 | ![rescript-logger](./example.png) 9 | 10 | ## Features 11 | - Zero runtime in production builds. 12 | - Multiple logging levels. 13 | - Customizable verbosity. 14 | - `[@log]` helper. 15 | - [`@rescript/react`](https://github.com/rescript-lang/rescript-react) integration. 16 | - Custom loggers. 17 | - Logging in libraries. 18 | 19 | > ### ShakaCode 20 | > If you are looking for help with the development and optimization of your project, [ShakaCode](https://www.shakacode.com) can help you to take the reliability and performance of your app to the next level. 21 | > 22 | > If you are a developer interested in working on ReScript / TypeScript / Rust / Ruby on Rails projects, [we're hiring](https://www.shakacode.com/career/)! 23 | 24 | ## Installation 25 | Get the package: 26 | 27 | ```shell 28 | # yarn 29 | yarn add rescript-logger 30 | # or npm 31 | npm install --save rescript-logger 32 | ``` 33 | 34 | Then add it to `bsconfig.json`: 35 | 36 | ```json 37 | "bs-dependencies": [ 38 | "rescript-logger" 39 | ], 40 | "ppx-flags": ["rescript-logger/ppx"] 41 | ``` 42 | 43 | ## Usage 44 | There are 5 log levels: 45 | - `trace` 46 | - `debug` 47 | - `info` 48 | - `warn` 49 | - `error` 50 | 51 | You can log message of specific level using appropriate macros: 52 | 53 | ```reason 54 | // ReScript 55 | %log.info("Info message") 56 | %log.error("Error message") 57 | 58 | // Reason 59 | [%log.info "Info message"]; 60 | [%log.error "Error message"]; 61 | ``` 62 | 63 | ### Additional data 64 | You can add data to log entry like this: 65 | 66 | ```reason 67 | // ReScript 68 | %log.info( 69 | "Info message" 70 | ("Foo", 42) 71 | ) 72 | %log.info( 73 | "Info message" 74 | ("Foo", {x: 42}) 75 | ("Bar", [1, 2, 3]) 76 | ) 77 | 78 | // Reason 79 | [%log.info "Info message"; ("Foo", 42)]; 80 | [%log.info 81 | "Info message"; 82 | ("Foo", {x: 42}); 83 | ("Bar", [1, 2, 3]); 84 | ]; 85 | ``` 86 | 87 | Currently, logger can accept up to 7 additional entries. 88 | 89 | ### Verbosity customization 90 | Output verbosity can be customized by providing specific **log level** and/or **code locations**. 91 | 92 | #### Log level 93 | You can set maximum log level via environment variable `RES_LOG`. 94 | 95 | Let's say you want to log only warnings and errors. To make it happen, run your build like this: 96 | 97 | ```shell 98 | RES_LOG=warn rescript build 99 | ``` 100 | 101 | Available `RES_LOG` values: 102 | - `*`: log everything 103 | - `trace`: basically, the same as `*` 104 | - `debug`: log everything except `trace` level messages 105 | - `info`: log everything except `trace` & `debug` level messages 106 | - `warn`: log `warn` & `error` messages only 107 | - `error`: log `error` messages only 108 | - `off`: don't log anything 109 | 110 | If `RES_LOG` is set to `off`, nothing will be logged and none of the log entries will appear in your JS assets. 111 | 112 | In case if `RES_LOG` environment variable is not set, log level `warn` will be used. 113 | 114 | Also, see [Usage in libraries](#usage-in-libraries). 115 | 116 | #### Code location 117 | If you want to focus on logging from specific part(s) of your code, you can use `RES_LOG_ONLY` environment variable. 118 | 119 | For example, if you want to see logs only from module `Test`, run the build as following: 120 | 121 | ```shell 122 | RES_LOG_ONLY=Test rescript build 123 | ``` 124 | 125 | You can pass submodules and functions to it as well. If you want to log from multiple locations, separate them by `,`. 126 | 127 | Consider the following source: 128 | 129 | ```reason 130 | // Test.res 131 | %log.warn("Top level message") 132 | 133 | module Submodule1 = { 134 | %log.warn("Message from Submodule1") 135 | } 136 | 137 | module Submodule2 = { 138 | %log.warn("Message from Submodule2") 139 | 140 | let fn = () => %log.warn("Message from function within Submodule2") 141 | fn() 142 | } 143 | ``` 144 | 145 | Here is what will be logged with different build configurations: 146 | 147 | ``` 148 | # build 149 | RES_LOG_ONLY=Test rescript build 150 | 151 | # output 152 | WARNING [Test] Top level message 153 | WARNING [Test.Submodule1] Message from Submodule1 154 | WARNING [Test.Submodule2] Message from Submodule2 155 | WARNING [Test.Submodule2.fn] Message from function within Submodule2 156 | 157 | # build 158 | RES_LOG_ONLY=Test.Submodule2 rescript build 159 | 160 | # output 161 | WARNING [Test.Submodule2] Message from Submodule2 162 | WARNING [Test.Submodule2.fn] Message from function within Submodule2 163 | 164 | # build 165 | RES_LOG_ONLY=Test.Submodule1,Test.Submodule2.fn rescript build 166 | 167 | # output 168 | WARNING [Test.Submodule1] Message from Submodule1 169 | WARNING [Test.Submodule2.fn] Message from function within Submodule2 170 | ``` 171 | 172 | ### `[@log]` helper 173 | This helper can be placed in front of any `switch` expression with constructor patterns and it will inject debug expressions into each branch. 174 | 175 | ```reason 176 | // ReScript 177 | let _ = 178 | x => 179 | @log 180 | switch x { 181 | | A => "A" 182 | | B(b) => b 183 | } 184 | 185 | // Reason 186 | let _ = 187 | x => 188 | [@log] 189 | switch (x) { 190 | | A => "A" 191 | | B(b) => b 192 | } 193 | ``` 194 | 195 | Without a `@log` helper, an equivalent would be: 196 | 197 | ```reason 198 | // ReScript 199 | let _ = 200 | x => 201 | switch (x) { 202 | | A => 203 | %log.debug("A") 204 | "A" 205 | | B(b) => 206 | %log.debug("B with payload" ("b", b)) 207 | b 208 | } 209 | 210 | // Reason 211 | let _ = 212 | x => 213 | switch (x) { 214 | | A => 215 | [%log.debug "A"]; 216 | "A"; 217 | | B(b) => 218 | [%log.debug "B with payload"; ("b", b)]; 219 | b; 220 | } 221 | ``` 222 | 223 | You can pass optional custom namespace to helper like this: `@log("MyNamespace")`. 224 | 225 | `[@log]` helper works only for `switch` expressions with constructor patterns, for now. Let us know [in the issues](/issues) if you need to handle more cases. 226 | 227 | ### `@rescript/react` integration 228 | Using `@log` helper, you can log dispatched actions in your components. 229 | 230 | Annotate `reducer` function like this: 231 | 232 | ```reason 233 | // ReScript 234 | let reducer = 235 | (state, action) => 236 | @log 237 | switch action { 238 | ... 239 | } 240 | 241 | // Reason 242 | let reducer = 243 | (state, action) => 244 | [@log] 245 | switch (action) { 246 | ... 247 | } 248 | ``` 249 | 250 | These entries are logged on the `debug` level so none of it will appear in your production builds. 251 | 252 | ### Custom loggers 253 | `rescript-logger` ships with 4 loggers: 254 | - `ReScriptLogger.Browser` (default) 255 | - `ReScriptLogger.Node` 256 | - `ReScriptLogger.Edge` (to use in edge environment, such as Cloudflare Workers) 257 | - `ReScriptLogger.Universal` (picks either `Browser` or `Node` logger at runtime depending on an environment, useful for apps with SSR) 258 | 259 | And you can easily plug your own. 260 | 261 | For example, in development, you want to log everything to console using default logger, but in production, you want to disable console logging and send `error` level events to bug tracker. 262 | 263 | To implement your own logger, you need to create a module (e.g. `BugTracker.re`) and set the following environment variables for production build. 264 | 265 | ``` 266 | RES_LOG=error 267 | RES_LOGGER=BugTracker 268 | ``` 269 | 270 | Considering that you want to log only `error` level messages, you need to create functions only for errors logging. 271 | 272 | ```reason 273 | // BugTracker.res 274 | 275 | let error = (loc, msg) => BugTrackerSDK.notify(`${msg} in ${loc.rootModule}`) 276 | 277 | let error1 = 278 | ( 279 | loc, 280 | msg, 281 | (label, payload), 282 | ) => 283 | BugTrackerSDK.notify( 284 | `${msg} in ${loc.rootModule}`, 285 | [|(label, payload)|], 286 | ); 287 | 288 | let error2 = 289 | ( 290 | loc, 291 | msg, 292 | (label1, payload1), 293 | (label2, payload2), 294 | ) => 295 | BugTrackerSDK.notify( 296 | `${msg} in ${loc.rootModule}`, 297 | [| 298 | (label1, payload1), 299 | (label2, payload2), 300 | |], 301 | ); 302 | 303 | // Up to 7 304 | ``` 305 | 306 | The first argument `loc` is a `ReScriptLogger.Location.t` record. It's passed by PPX and contains the location data. 307 | 308 | ```reason 309 | type t = { 310 | rootModule: string, 311 | subModulePath: list, 312 | value: option, 313 | fullPath: string, 314 | filePath: string, 315 | } 316 | ``` 317 | 318 | If `Test.Submodule.fn` gets called, logger would receive the following location: 319 | 320 | ```reason 321 | // Test.res 322 | module Submodule = { 323 | let fn = () => %log.warn("Warn!") 324 | } 325 | 326 | // Location 327 | { 328 | rootModule: "Test", 329 | subModulePath: list{"Submodule"}, 330 | value: Some("fn"), 331 | fullPath: "Test.Submodule.fn", 332 | filePath: "/absolute/path/to/project/src/Test.res", 333 | } 334 | ``` 335 | 336 | --- 337 | Note, you don't have to re-implement all functions from the default logger, only the ones you actually use. Don't worry to forget to implement something. If later on, you will attempt to use unimplemented method it will be compile time error. 338 | 339 | ### Usage in libraries 340 | If you develop a library and want to use `rescript-logger` during development process, you can do so without spamming output of consumers of your library. 341 | 342 | `rescript-logger/ppx` accepts `--lib` flag: 343 | 344 | ```json 345 | "ppx-flags": [ 346 | ["rescript-logger/ppx", "--lib=my-lib"] 347 | ] 348 | ``` 349 | 350 | Once this flag is passed, you need to provide special value of `RES_LOG` to log your entries: 351 | 352 | ```shell 353 | RES_LOG=my-lib=* rescript build 354 | ``` 355 | 356 | If consumers of your lib would like to see log output from your lib, they can do so too by extending a value of `RES_LOG` variable: 357 | 358 | ```shell 359 | RES_LOG=*,my-lib=error rescript build 360 | ``` 361 | 362 | Few more examples to illustrate how it works: 363 | 364 | ```shell 365 | # log everything from application code only 366 | RES_LOG=* rescript build 367 | 368 | # log everything from application code 369 | # log errors from `my-lib` 370 | RES_LOG=*,my-lib=error rescript build 371 | 372 | # log everything from application code 373 | # log errors from `my-lib-1` 374 | # log warnings and errors from `my-lib-2` 375 | RES_LOG=*,my-lib-1=error,my-lib-2=warn rescript build 376 | ``` 377 | 378 | ## Caveats 379 | **Logging is disabled after file save**
380 | If you run `bsb` via editor integration, make sure editor picked up `RES_LOG` variable. E.g. if you use Atom run it like this: 381 | 382 | ```shell 383 | RES_LOG=info atom . 384 | ``` 385 | 386 | If your editor is telling you, variables used in ppx are unused, you can either: 387 | 1. prefix such variables with `_` 388 | 2. or open editor with `RES_LOG` variable set to appropriate level. 389 | 390 | **Changing value of `RES_LOG`/`RES_LOGGER`/`RES_LOG_ONLY` doesn't make any effect**
391 | When you change a value of environment variable, `rescript clean` before the next build. 392 | 393 | ## Developing 394 | Repo consists of 2 parts: 395 | - ReScript lib: dependencies are managed by `yarn` 396 | - OCaml PPX: dependencies are managed either by `nix` (in development) or `esy` (in development and/or on CI) 397 | 398 | ### Nix flow 399 | Clone repo and either enter the Nix shell: 400 | 401 | ``` 402 | nix-shell 403 | ``` 404 | 405 | Or use [`direnv`](https://direnv.net/) and create `.envrc` file in the root directory of the project with the folowing content: 406 | 407 | ``` 408 | use nix 409 | ``` 410 | 411 | Then install deps: 412 | 413 | ```shell 414 | yarn install 415 | ``` 416 | 417 | Build loggers and ppx: 418 | 419 | ```shell 420 | dune build 421 | cd lib && yarn run build 422 | cd ../examples && yarn run build 423 | ``` 424 | 425 | ### Devbox flow 426 | Clone repo and either enter the Devbox shell: 427 | 428 | ``` 429 | devbox shell 430 | ``` 431 | 432 | Or use [`direnv`](https://direnv.net/) and create `.envrc` file in the root directory of the project by running: 433 | 434 | ``` 435 | devbox generate direnv --print-envrc 436 | ``` 437 | 438 | Then install deps: 439 | 440 | ```shell 441 | yarn install 442 | ``` 443 | 444 | Build loggers and ppx: 445 | 446 | ```shell 447 | devbox run build 448 | cd lib && yarn run build 449 | cd ../examples && yarn run build 450 | ``` 451 | 452 | ### Esy flow 453 | Clone repo and install deps: 454 | 455 | ```shell 456 | esy install 457 | yarn install 458 | ``` 459 | 460 | Build loggers and ppx: 461 | 462 | ```shell 463 | esy build 464 | cd lib && yarn run build 465 | cd ../examples && yarn run build 466 | ``` 467 | 468 | ### Auto-formatting 469 | Note, this project doesn't use auto-formatting in OCaml files (`*.ml`), so if you're intended to contribute, please, turn off auto-formatting in the editor while editing such files. 470 | 471 | ## Supporters 472 | 473 | 474 | JetBrains 475 | 476 | 477 | 478 | 479 | 480 | ScoutAPM 481 | 482 | 483 |
484 | 485 | 486 | 487 | 488 | BrowserStack 489 | 490 | 491 | 492 | Rails Autoscale 493 | 494 | 495 | Honeybadger 496 | 497 | 498 |
499 |
500 | 501 | The following companies support our open source projects, and ShakaCode uses their products! 502 | -------------------------------------------------------------------------------- /devbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "ocamlPackages.ocaml", 4 | "ocamlPackages.dune_3", 5 | "ocamlPackages.findlib", 6 | "ocamlPackages.ppxlib", 7 | "ocamlPackages.alcotest", 8 | "ocamlPackages.ocaml-lsp", 9 | "nodejs", 10 | "yarn" 11 | ], 12 | "shell": { 13 | "init_hook": [ 14 | "export PATH=$PATH:node_modules/.bin" 15 | ], 16 | "scripts": { 17 | "build": "dune build", 18 | "test": "dune exec test.exe" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /devbox.lock: -------------------------------------------------------------------------------- 1 | { 2 | "lockfile_version": "1", 3 | "packages": { 4 | "nodejs": { 5 | "resolved": "github:NixOS/nixpkgs/f80ac848e3d6f0c12c52758c0f25c10c97ca3b62#nodejs", 6 | "source": "nixpkg" 7 | }, 8 | "ocamlPackages.alcotest": { 9 | "resolved": "github:NixOS/nixpkgs/75a52265bda7fd25e06e3a67dee3f0354e73243c#ocamlPackages.alcotest", 10 | "source": "nixpkg" 11 | }, 12 | "ocamlPackages.dune_3": { 13 | "resolved": "github:NixOS/nixpkgs/75a52265bda7fd25e06e3a67dee3f0354e73243c#ocamlPackages.dune_3", 14 | "source": "nixpkg" 15 | }, 16 | "ocamlPackages.findlib": { 17 | "resolved": "github:NixOS/nixpkgs/75a52265bda7fd25e06e3a67dee3f0354e73243c#ocamlPackages.findlib", 18 | "source": "nixpkg" 19 | }, 20 | "ocamlPackages.ocaml": { 21 | "resolved": "github:NixOS/nixpkgs/75a52265bda7fd25e06e3a67dee3f0354e73243c#ocamlPackages.ocaml", 22 | "source": "nixpkg" 23 | }, 24 | "ocamlPackages.ocaml-lsp": { 25 | "resolved": "github:NixOS/nixpkgs/75a52265bda7fd25e06e3a67dee3f0354e73243c#ocamlPackages.ocaml-lsp", 26 | "source": "nixpkg" 27 | }, 28 | "ocamlPackages.ppxlib": { 29 | "resolved": "github:NixOS/nixpkgs/75a52265bda7fd25e06e3a67dee3f0354e73243c#ocamlPackages.ppxlib", 30 | "source": "nixpkg" 31 | }, 32 | "yarn": { 33 | "resolved": "github:NixOS/nixpkgs/f80ac848e3d6f0c12c52758c0f25c10c97ca3b62#yarn", 34 | "source": "nixpkg" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 2.6) 2 | (name rescript-logger-ppx) 3 | -------------------------------------------------------------------------------- /dune-workspace: -------------------------------------------------------------------------------- 1 | (lang dune 2.6) 2 | -------------------------------------------------------------------------------- /example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakacode/rescript-logger/ec688eadb1513991aa084380cf4013f7500d14b4/example.png -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rescript-logger-examples", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "rescript build" 7 | }, 8 | "devDependencies": { 9 | "rescript": "11.0.1", 10 | "rescript-logger": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/rescript.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rescript-logger-examples", 3 | "sources": [ 4 | { 5 | "dir": "src", 6 | "subdirs": true 7 | } 8 | ], 9 | "bs-dependencies": [ 10 | "rescript-logger" 11 | ], 12 | "package-specs": { 13 | "module": "es6", 14 | "in-source": true 15 | }, 16 | "ppx-flags": [ 17 | [ 18 | "../_build/default/ppx/bin/bin.exe" 19 | ] 20 | ], 21 | "suffix": ".res.js" 22 | } 23 | -------------------------------------------------------------------------------- /examples/src/ReScript.res: -------------------------------------------------------------------------------- 1 | let something = Some("thing") 2 | 3 | %log.trace("Trace message") 4 | %log.trace( 5 | "Trace message" 6 | ("1", 42) 7 | ) 8 | %log.trace( 9 | "Trace message" 10 | ("1", 42) 11 | ("2", {"x": 42}) 12 | ) 13 | %log.trace( 14 | "Trace message" 15 | ("1", 42) 16 | ("2", {"x": 42}) 17 | ("3", something) 18 | ) 19 | %log.trace( 20 | "Trace message" 21 | ("1", 42) 22 | ("2", {"x": 42}) 23 | ("3", something) 24 | ("4", list{1, 2, 4}) 25 | ) 26 | %log.trace( 27 | "Trace message" 28 | ("1", 42) 29 | ("2", {"x": 42}) 30 | ("3", something) 31 | ("4", list{1, 2, 4}) 32 | ("5", [1, 2, 4]) 33 | ) 34 | %log.trace( 35 | "Trace message" 36 | ("1", 42) 37 | ("2", {"x": 42}) 38 | ("3", something) 39 | ("4", list{1, 2, 4}) 40 | ("5", [1, 2, 4]) 41 | ("6", true) 42 | ) 43 | %log.trace( 44 | "Trace message" 45 | ("1", 42) 46 | ("2", {"x": 42}) 47 | ("3", something) 48 | ("4", list{1, 2, 4}) 49 | ("5", [1, 2, 4]) 50 | ("6", true) 51 | ("7", #x) 52 | ) 53 | 54 | %log.debug("Debug message") 55 | %log.debug( 56 | "Debug message" 57 | ("1", 42) 58 | ) 59 | %log.debug( 60 | "Debug message" 61 | ("1", 42) 62 | ("2", {"x": 42}) 63 | ) 64 | %log.debug( 65 | "Debug message" 66 | ("1", 42) 67 | ("2", {"x": 42}) 68 | ("3", something) 69 | ) 70 | %log.debug( 71 | "Debug message" 72 | ("1", 42) 73 | ("2", {"x": 42}) 74 | ("3", something) 75 | ("4", list{1, 2, 4}) 76 | ) 77 | %log.debug( 78 | "Debug message" 79 | ("1", 42) 80 | ("2", {"x": 42}) 81 | ("3", something) 82 | ("4", list{1, 2, 4}) 83 | ("5", [1, 2, 4]) 84 | ) 85 | %log.debug( 86 | "Debug message" 87 | ("1", 42) 88 | ("2", {"x": 42}) 89 | ("3", something) 90 | ("4", list{1, 2, 4}) 91 | ("5", [1, 2, 4]) 92 | ("6", true) 93 | ) 94 | %log.debug( 95 | "Debug message" 96 | ("1", 42) 97 | ("2", {"x": 42}) 98 | ("3", something) 99 | ("4", list{1, 2, 4}) 100 | ("5", [1, 2, 4]) 101 | ("6", true) 102 | ("7", #x) 103 | ) 104 | 105 | %log.info("Info message") 106 | %log.info( 107 | "Info message" 108 | ("1", 42) 109 | ) 110 | %log.info( 111 | "Info message" 112 | ("1", 42) 113 | ("2", {"x": 42}) 114 | ) 115 | %log.info( 116 | "Info message" 117 | ("1", 42) 118 | ("2", {"x": 42}) 119 | ("3", something) 120 | ) 121 | %log.info( 122 | "Info message" 123 | ("1", 42) 124 | ("2", {"x": 42}) 125 | ("3", something) 126 | ("4", list{1, 2, 4}) 127 | ) 128 | %log.info( 129 | "Info message" 130 | ("1", 42) 131 | ("2", {"x": 42}) 132 | ("3", something) 133 | ("4", list{1, 2, 4}) 134 | ("5", [1, 2, 4]) 135 | ) 136 | %log.info( 137 | "Info message" 138 | ("1", 42) 139 | ("2", {"x": 42}) 140 | ("3", something) 141 | ("4", list{1, 2, 4}) 142 | ("5", [1, 2, 4]) 143 | ("6", true) 144 | ) 145 | %log.info( 146 | "Info message" 147 | ("1", 42) 148 | ("2", {"x": 42}) 149 | ("3", something) 150 | ("4", list{1, 2, 4}) 151 | ("5", [1, 2, 4]) 152 | ("6", true) 153 | ("7", #x) 154 | ) 155 | 156 | %log.warn("Warn message") 157 | %log.warn( 158 | "Warn message" 159 | ("1", 42) 160 | ) 161 | %log.warn( 162 | "Warn message" 163 | ("1", 42) 164 | ("2", {"x": 42}) 165 | ) 166 | %log.warn( 167 | "Warn message" 168 | ("1", 42) 169 | ("2", {"x": 42}) 170 | ("3", something) 171 | ) 172 | %log.warn( 173 | "Warn message" 174 | ("1", 42) 175 | ("2", {"x": 42}) 176 | ("3", something) 177 | ("4", list{1, 2, 4}) 178 | ) 179 | %log.warn( 180 | "Warn message" 181 | ("1", 42) 182 | ("2", {"x": 42}) 183 | ("3", something) 184 | ("4", list{1, 2, 4}) 185 | ("5", [1, 2, 4]) 186 | ) 187 | %log.warn( 188 | "Warn message" 189 | ("1", 42) 190 | ("2", {"x": 42}) 191 | ("3", something) 192 | ("4", list{1, 2, 4}) 193 | ("5", [1, 2, 4]) 194 | ("6", true) 195 | ) 196 | %log.warn( 197 | "Warn message" 198 | ("1", 42) 199 | ("2", {"x": 42}) 200 | ("3", something) 201 | ("4", list{1, 2, 4}) 202 | ("5", [1, 2, 4]) 203 | ("6", true) 204 | ("7", #x) 205 | ) 206 | 207 | %log.error("Error message") 208 | %log.error( 209 | "Error message" 210 | ("1", 42) 211 | ) 212 | %log.error( 213 | "Error message" 214 | ("1", 42) 215 | ("2", {"x": 42}) 216 | ) 217 | %log.error( 218 | "Error message" 219 | ("1", 42) 220 | ("2", {"x": 42}) 221 | ("3", something) 222 | ) 223 | %log.error( 224 | "Error message" 225 | ("1", 42) 226 | ("2", {"x": 42}) 227 | ("3", something) 228 | ("4", list{1, 2, 4}) 229 | ) 230 | %log.error( 231 | "Error message" 232 | ("1", 42) 233 | ("2", {"x": 42}) 234 | ("3", something) 235 | ("4", list{1, 2, 4}) 236 | ("5", [1, 2, 4]) 237 | ) 238 | %log.error( 239 | "Error message" 240 | ("1", 42) 241 | ("2", {"x": 42}) 242 | ("3", something) 243 | ("4", list{1, 2, 4}) 244 | ("5", [1, 2, 4]) 245 | ("6", true) 246 | ) 247 | %log.error( 248 | "Error message" 249 | ("1", 42) 250 | ("2", {"x": 42}) 251 | ("3", something) 252 | ("4", list{1, 2, 4}) 253 | ("5", [1, 2, 4]) 254 | ("6", true) 255 | ("7", #x) 256 | ) 257 | 258 | module Inner = { 259 | %log.error("Error message in module") 260 | 261 | let fn = x => { 262 | %log.error( 263 | "Error message in module within a function" 264 | ("X", x) 265 | ) 266 | x 267 | } 268 | } 269 | 270 | module Very = { 271 | module Deep = { 272 | module Module = { 273 | %log.info("Info message from the Very.Deep.Module") 274 | } 275 | } 276 | } 277 | 278 | type state 279 | type action = 280 | | A 281 | | B(string) 282 | | C(string, string) 283 | | D(string, string, string) 284 | | E(string, string, string, string) 285 | | F(string, string, string, string, string) 286 | | G(string, string, string, string, string, string) 287 | | H(string, string, string, string, string, string, string) 288 | type component = {reducer: (action, state) => string} 289 | let make = { 290 | reducer: (action, _state) => 291 | @log 292 | switch action { 293 | | A => "a" 294 | | B(x) => 295 | %log.trace( 296 | "Ext" 297 | ("within", "@log") 298 | ) 299 | x 300 | | C(_x1, x2) => x2 301 | | D(_x1, _x2, x3) => x3 302 | | E(_x1, _x2, _x3, x4) => x4 303 | | F(_x1, _x2, _x3, _x4, x5) => x5 304 | | G(_x1, _x2, _x3, _x4, _x5, x6) => x6 305 | | H(_x1, _x2, _x3, _x4, _x5, _x6, x7) => x7 306 | }, 307 | } 308 | 309 | type ns = 310 | | A 311 | | B(string) 312 | | C(int) 313 | let ns = x => 314 | @log("Namespace") 315 | switch x { 316 | | A => "A" 317 | | B(x) => x 318 | | C(_) => "C" 319 | } 320 | let s: string = ns(B("b")) 321 | 322 | let noop = x => 323 | @log 324 | switch x { 325 | | "" => "a" 326 | | _ => "b" 327 | } 328 | -------------------------------------------------------------------------------- /lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rescript-logger", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "rescript build -w", 7 | "build": "rescript build" 8 | }, 9 | "devDependencies": { 10 | "rescript": "11.0.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/rescript.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rescript-logger", 3 | "namespace": "ReScriptLogger", 4 | "sources": [ 5 | { 6 | "dir": "src", 7 | "subdirs": true 8 | } 9 | ], 10 | "package-specs": { 11 | "module": "es6", 12 | "in-source": true 13 | }, 14 | "suffix": ".res.js" 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/Interface.res: -------------------------------------------------------------------------------- 1 | module type Logger = { 2 | let trace: (Location.t, 'x) => unit 3 | let trace1: (Location.t, 'x, (string, 'x1)) => unit 4 | let trace2: (Location.t, 'x, (string, 'x1), (string, 'x2)) => unit 5 | let trace3: (Location.t, 'x, (string, 'x1), (string, 'x2), (string, 'x3)) => unit 6 | let trace4: (Location.t, 'x, (string, 'x1), (string, 'x2), (string, 'x3), (string, 'x4)) => unit 7 | let trace5: ( 8 | Location.t, 9 | 'x, 10 | (string, 'x1), 11 | (string, 'x2), 12 | (string, 'x3), 13 | (string, 'x4), 14 | (string, 'x5), 15 | ) => unit 16 | let trace6: ( 17 | Location.t, 18 | 'x, 19 | (string, 'x1), 20 | (string, 'x2), 21 | (string, 'x3), 22 | (string, 'x4), 23 | (string, 'x5), 24 | (string, 'x6), 25 | ) => unit 26 | let trace7: ( 27 | Location.t, 28 | 'x, 29 | (string, 'x1), 30 | (string, 'x2), 31 | (string, 'x3), 32 | (string, 'x4), 33 | (string, 'x5), 34 | (string, 'x6), 35 | (string, 'x7), 36 | ) => unit 37 | 38 | let debug: (Location.t, 'x) => unit 39 | let debug1: (Location.t, 'x, (string, 'x1)) => unit 40 | let debug2: (Location.t, 'x, (string, 'x1), (string, 'x2)) => unit 41 | let debug3: (Location.t, 'x, (string, 'x1), (string, 'x2), (string, 'x3)) => unit 42 | let debug4: (Location.t, 'x, (string, 'x1), (string, 'x2), (string, 'x3), (string, 'x4)) => unit 43 | let debug5: ( 44 | Location.t, 45 | 'x, 46 | (string, 'x1), 47 | (string, 'x2), 48 | (string, 'x3), 49 | (string, 'x4), 50 | (string, 'x5), 51 | ) => unit 52 | let debug6: ( 53 | Location.t, 54 | 'x, 55 | (string, 'x1), 56 | (string, 'x2), 57 | (string, 'x3), 58 | (string, 'x4), 59 | (string, 'x5), 60 | (string, 'x6), 61 | ) => unit 62 | let debug7: ( 63 | Location.t, 64 | 'x, 65 | (string, 'x1), 66 | (string, 'x2), 67 | (string, 'x3), 68 | (string, 'x4), 69 | (string, 'x5), 70 | (string, 'x6), 71 | (string, 'x7), 72 | ) => unit 73 | 74 | let info: (Location.t, 'x) => unit 75 | let info1: (Location.t, 'x, (string, 'x1)) => unit 76 | let info2: (Location.t, 'x, (string, 'x1), (string, 'x2)) => unit 77 | let info3: (Location.t, 'x, (string, 'x1), (string, 'x2), (string, 'x3)) => unit 78 | let info4: (Location.t, 'x, (string, 'x1), (string, 'x2), (string, 'x3), (string, 'x4)) => unit 79 | let info5: ( 80 | Location.t, 81 | 'x, 82 | (string, 'x1), 83 | (string, 'x2), 84 | (string, 'x3), 85 | (string, 'x4), 86 | (string, 'x5), 87 | ) => unit 88 | let info6: ( 89 | Location.t, 90 | 'x, 91 | (string, 'x1), 92 | (string, 'x2), 93 | (string, 'x3), 94 | (string, 'x4), 95 | (string, 'x5), 96 | (string, 'x6), 97 | ) => unit 98 | let info7: ( 99 | Location.t, 100 | 'x, 101 | (string, 'x1), 102 | (string, 'x2), 103 | (string, 'x3), 104 | (string, 'x4), 105 | (string, 'x5), 106 | (string, 'x6), 107 | (string, 'x7), 108 | ) => unit 109 | 110 | let warn: (Location.t, 'x) => unit 111 | let warn1: (Location.t, 'x, (string, 'x1)) => unit 112 | let warn2: (Location.t, 'x, (string, 'x1), (string, 'x2)) => unit 113 | let warn3: (Location.t, 'x, (string, 'x1), (string, 'x2), (string, 'x3)) => unit 114 | let warn4: (Location.t, 'x, (string, 'x1), (string, 'x2), (string, 'x3), (string, 'x4)) => unit 115 | let warn5: ( 116 | Location.t, 117 | 'x, 118 | (string, 'x1), 119 | (string, 'x2), 120 | (string, 'x3), 121 | (string, 'x4), 122 | (string, 'x5), 123 | ) => unit 124 | let warn6: ( 125 | Location.t, 126 | 'x, 127 | (string, 'x1), 128 | (string, 'x2), 129 | (string, 'x3), 130 | (string, 'x4), 131 | (string, 'x5), 132 | (string, 'x6), 133 | ) => unit 134 | let warn7: ( 135 | Location.t, 136 | 'x, 137 | (string, 'x1), 138 | (string, 'x2), 139 | (string, 'x3), 140 | (string, 'x4), 141 | (string, 'x5), 142 | (string, 'x6), 143 | (string, 'x7), 144 | ) => unit 145 | 146 | let error: (Location.t, 'x) => unit 147 | let error1: (Location.t, 'x, (string, 'x1)) => unit 148 | let error2: (Location.t, 'x, (string, 'x1), (string, 'x2)) => unit 149 | let error3: (Location.t, 'x, (string, 'x1), (string, 'x2), (string, 'x3)) => unit 150 | let error4: (Location.t, 'x, (string, 'x1), (string, 'x2), (string, 'x3), (string, 'x4)) => unit 151 | let error5: ( 152 | Location.t, 153 | 'x, 154 | (string, 'x1), 155 | (string, 'x2), 156 | (string, 'x3), 157 | (string, 'x4), 158 | (string, 'x5), 159 | ) => unit 160 | let error6: ( 161 | Location.t, 162 | 'x, 163 | (string, 'x1), 164 | (string, 'x2), 165 | (string, 'x3), 166 | (string, 'x4), 167 | (string, 'x5), 168 | (string, 'x6), 169 | ) => unit 170 | let error7: ( 171 | Location.t, 172 | 'x, 173 | (string, 'x1), 174 | (string, 'x2), 175 | (string, 'x3), 176 | (string, 'x4), 177 | (string, 'x5), 178 | (string, 'x6), 179 | (string, 'x7), 180 | ) => unit 181 | } 182 | -------------------------------------------------------------------------------- /lib/src/Location.res: -------------------------------------------------------------------------------- 1 | type t = { 2 | rootModule: string, 3 | subModulePath: list, 4 | value: option, 5 | fullPath: string, 6 | } 7 | 8 | let format = x => `[${x.fullPath}]` 9 | -------------------------------------------------------------------------------- /lib/src/loggers/Browser.res: -------------------------------------------------------------------------------- 1 | @val @scope("console") external log: ('a, 'b) => unit = "log" 2 | @val @scope("console") external groupEnd: unit => unit = "groupEnd" 3 | 4 | // Level: Trace 5 | @val @scope("console") 6 | external traceGroup: ( 7 | @as("%c TRACE ") _, 8 | @as("background: #636363; color: #fff;") _, 9 | 'a, 10 | 'b, 11 | ) => unit = "group" 12 | 13 | @val @scope("console") 14 | external traceGroupCollapsed: ( 15 | @as("%c TRACE ") _, 16 | @as("background: #636363; color: #fff;") _, 17 | 'a, 18 | 'b, 19 | ) => unit = "groupCollapsed" 20 | 21 | let trace = (loc: Location.t, x: 'x) => { 22 | loc->Location.format->traceGroupCollapsed(x) 23 | groupEnd() 24 | } 25 | 26 | let trace1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 27 | loc->Location.format->traceGroup(x) 28 | log(l1 ++ ":", x1) 29 | groupEnd() 30 | } 31 | 32 | let trace2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 33 | loc->Location.format->traceGroup(x) 34 | log(l1 ++ ":", x1) 35 | log(l2 ++ ":", x2) 36 | groupEnd() 37 | } 38 | 39 | let trace3 = ( 40 | loc: Location.t, 41 | x: 'x, 42 | (l1, x1): (string, 'x1), 43 | (l2, x2): (string, 'x2), 44 | (l3, x3): (string, 'x3), 45 | ) => { 46 | loc->Location.format->traceGroup(x) 47 | log(l1 ++ ":", x1) 48 | log(l2 ++ ":", x2) 49 | log(l3 ++ ":", x3) 50 | groupEnd() 51 | } 52 | 53 | let trace4 = ( 54 | loc: Location.t, 55 | x: 'x, 56 | (l1, x1): (string, 'x1), 57 | (l2, x2): (string, 'x2), 58 | (l3, x3): (string, 'x3), 59 | (l4, x4): (string, 'x4), 60 | ) => { 61 | loc->Location.format->traceGroup(x) 62 | log(l1 ++ ":", x1) 63 | log(l2 ++ ":", x2) 64 | log(l3 ++ ":", x3) 65 | log(l4 ++ ":", x4) 66 | groupEnd() 67 | } 68 | 69 | let trace5 = ( 70 | loc: Location.t, 71 | x: 'x, 72 | (l1, x1): (string, 'x1), 73 | (l2, x2): (string, 'x2), 74 | (l3, x3): (string, 'x3), 75 | (l4, x4): (string, 'x4), 76 | (l5, x5): (string, 'x5), 77 | ) => { 78 | loc->Location.format->traceGroup(x) 79 | log(l1 ++ ":", x1) 80 | log(l2 ++ ":", x2) 81 | log(l3 ++ ":", x3) 82 | log(l4 ++ ":", x4) 83 | log(l5 ++ ":", x5) 84 | groupEnd() 85 | } 86 | 87 | let trace6 = ( 88 | loc: Location.t, 89 | x: 'x, 90 | (l1, x1): (string, 'x1), 91 | (l2, x2): (string, 'x2), 92 | (l3, x3): (string, 'x3), 93 | (l4, x4): (string, 'x4), 94 | (l5, x5): (string, 'x5), 95 | (l6, x6): (string, 'x6), 96 | ) => { 97 | loc->Location.format->traceGroup(x) 98 | log(l1 ++ ":", x1) 99 | log(l2 ++ ":", x2) 100 | log(l3 ++ ":", x3) 101 | log(l4 ++ ":", x4) 102 | log(l5 ++ ":", x5) 103 | log(l6 ++ ":", x6) 104 | groupEnd() 105 | } 106 | 107 | let trace7 = ( 108 | loc: Location.t, 109 | x: 'x, 110 | (l1, x1): (string, 'x1), 111 | (l2, x2): (string, 'x2), 112 | (l3, x3): (string, 'x3), 113 | (l4, x4): (string, 'x4), 114 | (l5, x5): (string, 'x5), 115 | (l6, x6): (string, 'x6), 116 | (l7, x7): (string, 'x7), 117 | ) => { 118 | loc->Location.format->traceGroup(x) 119 | log(l1 ++ ":", x1) 120 | log(l2 ++ ":", x2) 121 | log(l3 ++ ":", x3) 122 | log(l4 ++ ":", x4) 123 | log(l5 ++ ":", x5) 124 | log(l6 ++ ":", x6) 125 | log(l7 ++ ":", x7) 126 | groupEnd() 127 | } 128 | 129 | // Level: Debug 130 | @val @scope("console") 131 | external debugGroup: ( 132 | @as("%c DEBUG ") _, 133 | @as("background: #82658c; color: #fff;") _, 134 | 'a, 135 | 'b, 136 | ) => unit = "group" 137 | 138 | @val @scope("console") 139 | external debugGroupCollapsed: ( 140 | @as("%c DEBUG ") _, 141 | @as("background: #82658c; color: #fff;") _, 142 | 'a, 143 | 'b, 144 | ) => unit = "groupCollapsed" 145 | 146 | let debug = (loc: Location.t, x: 'x) => { 147 | loc->Location.format->debugGroupCollapsed(x) 148 | groupEnd() 149 | } 150 | 151 | let debug1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 152 | loc->Location.format->debugGroup(x) 153 | log(l1 ++ ":", x1) 154 | groupEnd() 155 | } 156 | 157 | let debug2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 158 | loc->Location.format->debugGroup(x) 159 | log(l1 ++ ":", x1) 160 | log(l2 ++ ":", x2) 161 | groupEnd() 162 | } 163 | 164 | let debug3 = ( 165 | loc: Location.t, 166 | x: 'x, 167 | (l1, x1): (string, 'x1), 168 | (l2, x2): (string, 'x2), 169 | (l3, x3): (string, 'x3), 170 | ) => { 171 | loc->Location.format->debugGroup(x) 172 | log(l1 ++ ":", x1) 173 | log(l2 ++ ":", x2) 174 | log(l3 ++ ":", x3) 175 | groupEnd() 176 | } 177 | 178 | let debug4 = ( 179 | loc: Location.t, 180 | x: 'x, 181 | (l1, x1): (string, 'x1), 182 | (l2, x2): (string, 'x2), 183 | (l3, x3): (string, 'x3), 184 | (l4, x4): (string, 'x4), 185 | ) => { 186 | loc->Location.format->debugGroup(x) 187 | log(l1 ++ ":", x1) 188 | log(l2 ++ ":", x2) 189 | log(l3 ++ ":", x3) 190 | log(l4 ++ ":", x4) 191 | groupEnd() 192 | } 193 | 194 | let debug5 = ( 195 | loc: Location.t, 196 | x: 'x, 197 | (l1, x1): (string, 'x1), 198 | (l2, x2): (string, 'x2), 199 | (l3, x3): (string, 'x3), 200 | (l4, x4): (string, 'x4), 201 | (l5, x5): (string, 'x5), 202 | ) => { 203 | loc->Location.format->debugGroup(x) 204 | log(l1 ++ ":", x1) 205 | log(l2 ++ ":", x2) 206 | log(l3 ++ ":", x3) 207 | log(l4 ++ ":", x4) 208 | log(l5 ++ ":", x5) 209 | groupEnd() 210 | } 211 | 212 | let debug6 = ( 213 | loc: Location.t, 214 | x: 'x, 215 | (l1, x1): (string, 'x1), 216 | (l2, x2): (string, 'x2), 217 | (l3, x3): (string, 'x3), 218 | (l4, x4): (string, 'x4), 219 | (l5, x5): (string, 'x5), 220 | (l6, x6): (string, 'x6), 221 | ) => { 222 | loc->Location.format->debugGroup(x) 223 | log(l1 ++ ":", x1) 224 | log(l2 ++ ":", x2) 225 | log(l3 ++ ":", x3) 226 | log(l4 ++ ":", x4) 227 | log(l5 ++ ":", x5) 228 | log(l6 ++ ":", x6) 229 | groupEnd() 230 | } 231 | 232 | let debug7 = ( 233 | loc: Location.t, 234 | x: 'x, 235 | (l1, x1): (string, 'x1), 236 | (l2, x2): (string, 'x2), 237 | (l3, x3): (string, 'x3), 238 | (l4, x4): (string, 'x4), 239 | (l5, x5): (string, 'x5), 240 | (l6, x6): (string, 'x6), 241 | (l7, x7): (string, 'x7), 242 | ) => { 243 | loc->Location.format->debugGroup(x) 244 | log(l1 ++ ":", x1) 245 | log(l2 ++ ":", x2) 246 | log(l3 ++ ":", x3) 247 | log(l4 ++ ":", x4) 248 | log(l5 ++ ":", x5) 249 | log(l6 ++ ":", x6) 250 | log(l7 ++ ":", x7) 251 | groupEnd() 252 | } 253 | 254 | // Level: Info 255 | @val @scope("console") 256 | external infoGroup: (@as("%c INFO ") _, @as("background: #29d; color: #fff;") _, 'a, 'b) => unit = 257 | "group" 258 | 259 | @val @scope("console") 260 | external infoGroupCollapsed: ( 261 | @as("%c INFO ") _, 262 | @as("background: #29d; color: #fff;") _, 263 | 'a, 264 | 'b, 265 | ) => unit = "groupCollapsed" 266 | 267 | let info = (loc: Location.t, x: 'x) => { 268 | loc->Location.format->infoGroupCollapsed(x) 269 | groupEnd() 270 | } 271 | 272 | let info1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 273 | loc->Location.format->infoGroup(x) 274 | log(l1 ++ ":", x1) 275 | groupEnd() 276 | } 277 | 278 | let info2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 279 | loc->Location.format->infoGroup(x) 280 | log(l1 ++ ":", x1) 281 | log(l2 ++ ":", x2) 282 | groupEnd() 283 | } 284 | 285 | let info3 = ( 286 | loc: Location.t, 287 | x: 'x, 288 | (l1, x1): (string, 'x1), 289 | (l2, x2): (string, 'x2), 290 | (l3, x3): (string, 'x3), 291 | ) => { 292 | loc->Location.format->infoGroup(x) 293 | log(l1 ++ ":", x1) 294 | log(l2 ++ ":", x2) 295 | log(l3 ++ ":", x3) 296 | groupEnd() 297 | } 298 | 299 | let info4 = ( 300 | loc: Location.t, 301 | x: 'x, 302 | (l1, x1): (string, 'x1), 303 | (l2, x2): (string, 'x2), 304 | (l3, x3): (string, 'x3), 305 | (l4, x4): (string, 'x4), 306 | ) => { 307 | loc->Location.format->infoGroup(x) 308 | log(l1 ++ ":", x1) 309 | log(l2 ++ ":", x2) 310 | log(l3 ++ ":", x3) 311 | log(l4 ++ ":", x4) 312 | groupEnd() 313 | } 314 | 315 | let info5 = ( 316 | loc: Location.t, 317 | x: 'x, 318 | (l1, x1): (string, 'x1), 319 | (l2, x2): (string, 'x2), 320 | (l3, x3): (string, 'x3), 321 | (l4, x4): (string, 'x4), 322 | (l5, x5): (string, 'x5), 323 | ) => { 324 | loc->Location.format->infoGroup(x) 325 | log(l1 ++ ":", x1) 326 | log(l2 ++ ":", x2) 327 | log(l3 ++ ":", x3) 328 | log(l4 ++ ":", x4) 329 | log(l5 ++ ":", x5) 330 | groupEnd() 331 | } 332 | 333 | let info6 = ( 334 | loc: Location.t, 335 | x: 'x, 336 | (l1, x1): (string, 'x1), 337 | (l2, x2): (string, 'x2), 338 | (l3, x3): (string, 'x3), 339 | (l4, x4): (string, 'x4), 340 | (l5, x5): (string, 'x5), 341 | (l6, x6): (string, 'x6), 342 | ) => { 343 | loc->Location.format->infoGroup(x) 344 | log(l1 ++ ":", x1) 345 | log(l2 ++ ":", x2) 346 | log(l3 ++ ":", x3) 347 | log(l4 ++ ":", x4) 348 | log(l5 ++ ":", x5) 349 | log(l6 ++ ":", x6) 350 | groupEnd() 351 | } 352 | 353 | let info7 = ( 354 | loc: Location.t, 355 | x: 'x, 356 | (l1, x1): (string, 'x1), 357 | (l2, x2): (string, 'x2), 358 | (l3, x3): (string, 'x3), 359 | (l4, x4): (string, 'x4), 360 | (l5, x5): (string, 'x5), 361 | (l6, x6): (string, 'x6), 362 | (l7, x7): (string, 'x7), 363 | ) => { 364 | loc->Location.format->infoGroup(x) 365 | log(l1 ++ ":", x1) 366 | log(l2 ++ ":", x2) 367 | log(l3 ++ ":", x3) 368 | log(l4 ++ ":", x4) 369 | log(l5 ++ ":", x5) 370 | log(l6 ++ ":", x6) 371 | log(l7 ++ ":", x7) 372 | groupEnd() 373 | } 374 | 375 | // Level: Warn 376 | @val @scope("console") 377 | external warnGroup: ( 378 | @as("%c WARNING ") _, 379 | @as("background: #fce473; color: #573a08;") _, 380 | 'a, 381 | 'b, 382 | ) => unit = "group" 383 | 384 | @val @scope("console") 385 | external warnGroupCollapsed: ( 386 | @as("%c WARNING ") _, 387 | @as("background: #fce473; color: #573a08;") _, 388 | 'a, 389 | 'b, 390 | ) => unit = "groupCollapsed" 391 | 392 | let warn = (loc: Location.t, x: 'x) => { 393 | loc->Location.format->warnGroupCollapsed(x) 394 | groupEnd() 395 | } 396 | 397 | let warn1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 398 | loc->Location.format->warnGroup(x) 399 | log(l1 ++ ":", x1) 400 | groupEnd() 401 | } 402 | 403 | let warn2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 404 | loc->Location.format->warnGroup(x) 405 | log(l1 ++ ":", x1) 406 | log(l2 ++ ":", x2) 407 | groupEnd() 408 | } 409 | 410 | let warn3 = ( 411 | loc: Location.t, 412 | x: 'x, 413 | (l1, x1): (string, 'x1), 414 | (l2, x2): (string, 'x2), 415 | (l3, x3): (string, 'x3), 416 | ) => { 417 | loc->Location.format->warnGroup(x) 418 | log(l1 ++ ":", x1) 419 | log(l2 ++ ":", x2) 420 | log(l3 ++ ":", x3) 421 | groupEnd() 422 | } 423 | 424 | let warn4 = ( 425 | loc: Location.t, 426 | x: 'x, 427 | (l1, x1): (string, 'x1), 428 | (l2, x2): (string, 'x2), 429 | (l3, x3): (string, 'x3), 430 | (l4, x4): (string, 'x4), 431 | ) => { 432 | loc->Location.format->warnGroup(x) 433 | log(l1 ++ ":", x1) 434 | log(l2 ++ ":", x2) 435 | log(l3 ++ ":", x3) 436 | log(l4 ++ ":", x4) 437 | groupEnd() 438 | } 439 | 440 | let warn5 = ( 441 | loc: Location.t, 442 | x: 'x, 443 | (l1, x1): (string, 'x1), 444 | (l2, x2): (string, 'x2), 445 | (l3, x3): (string, 'x3), 446 | (l4, x4): (string, 'x5), 447 | (l5, x5): (string, 'x6), 448 | ) => { 449 | loc->Location.format->warnGroup(x) 450 | log(l1 ++ ":", x1) 451 | log(l2 ++ ":", x2) 452 | log(l3 ++ ":", x3) 453 | log(l4 ++ ":", x4) 454 | log(l5 ++ ":", x5) 455 | groupEnd() 456 | } 457 | 458 | let warn6 = ( 459 | loc: Location.t, 460 | x: 'x, 461 | (l1, x1): (string, 'x1), 462 | (l2, x2): (string, 'x2), 463 | (l3, x3): (string, 'x3), 464 | (l4, x4): (string, 'x4), 465 | (l5, x5): (string, 'x5), 466 | (l6, x6): (string, 'x6), 467 | ) => { 468 | loc->Location.format->warnGroup(x) 469 | log(l1 ++ ":", x1) 470 | log(l2 ++ ":", x2) 471 | log(l3 ++ ":", x3) 472 | log(l4 ++ ":", x4) 473 | log(l5 ++ ":", x5) 474 | log(l6 ++ ":", x6) 475 | groupEnd() 476 | } 477 | 478 | let warn7 = ( 479 | loc: Location.t, 480 | x: 'x, 481 | (l1, x1): (string, 'x1), 482 | (l2, x2): (string, 'x2), 483 | (l3, x3): (string, 'x3), 484 | (l4, x4): (string, 'x4), 485 | (l5, x5): (string, 'x5), 486 | (l6, x6): (string, 'x6), 487 | (l7, x7): (string, 'x7), 488 | ) => { 489 | loc->Location.format->warnGroup(x) 490 | log(l1 ++ ":", x1) 491 | log(l2 ++ ":", x2) 492 | log(l3 ++ ":", x3) 493 | log(l4 ++ ":", x4) 494 | log(l5 ++ ":", x5) 495 | log(l6 ++ ":", x6) 496 | log(l7 ++ ":", x7) 497 | groupEnd() 498 | } 499 | 500 | // Level: Error 501 | @val @scope("console") 502 | external errorGroup: ( 503 | @as("%c ERROR ") _, 504 | @as("background: #d11a1a; color: #fff;") _, 505 | 'a, 506 | 'b, 507 | ) => unit = "group" 508 | 509 | @val @scope("console") 510 | external errorGroupCollapsed: ( 511 | @as("%c ERROR ") _, 512 | @as("background: #d11a1a; color: #fff;") _, 513 | 'a, 514 | 'b, 515 | ) => unit = "groupCollapsed" 516 | 517 | let error = (loc: Location.t, x: 'x) => { 518 | loc->Location.format->errorGroupCollapsed(x) 519 | groupEnd() 520 | } 521 | 522 | let error1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 523 | loc->Location.format->errorGroup(x) 524 | log(l1 ++ ":", x1) 525 | groupEnd() 526 | } 527 | 528 | let error2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 529 | loc->Location.format->errorGroup(x) 530 | log(l1 ++ ":", x1) 531 | log(l2 ++ ":", x2) 532 | groupEnd() 533 | } 534 | 535 | let error3 = ( 536 | loc: Location.t, 537 | x: 'x, 538 | (l1, x1): (string, 'x1), 539 | (l2, x2): (string, 'x2), 540 | (l3, x3): (string, 'x3), 541 | ) => { 542 | loc->Location.format->errorGroup(x) 543 | log(l1 ++ ":", x1) 544 | log(l2 ++ ":", x2) 545 | log(l3 ++ ":", x3) 546 | groupEnd() 547 | } 548 | 549 | let error4 = ( 550 | loc: Location.t, 551 | x: 'x, 552 | (l1, x1): (string, 'x1), 553 | (l2, x2): (string, 'x2), 554 | (l3, x3): (string, 'x3), 555 | (l4, x4): (string, 'x4), 556 | ) => { 557 | loc->Location.format->errorGroup(x) 558 | log(l1 ++ ":", x1) 559 | log(l2 ++ ":", x2) 560 | log(l3 ++ ":", x3) 561 | log(l4 ++ ":", x4) 562 | groupEnd() 563 | } 564 | 565 | let error5 = ( 566 | loc: Location.t, 567 | x: 'x, 568 | (l1, x1): (string, 'x1), 569 | (l2, x2): (string, 'x2), 570 | (l3, x3): (string, 'x3), 571 | (l4, x4): (string, 'x4), 572 | (l5, x5): (string, 'x5), 573 | ) => { 574 | loc->Location.format->errorGroup(x) 575 | log(l1 ++ ":", x1) 576 | log(l2 ++ ":", x2) 577 | log(l3 ++ ":", x3) 578 | log(l4 ++ ":", x4) 579 | log(l5 ++ ":", x5) 580 | groupEnd() 581 | } 582 | 583 | let error6 = ( 584 | loc: Location.t, 585 | x: 'x, 586 | (l1, x1): (string, 'x1), 587 | (l2, x2): (string, 'x2), 588 | (l3, x3): (string, 'x3), 589 | (l4, x4): (string, 'x4), 590 | (l5, x5): (string, 'x5), 591 | (l6, x6): (string, 'x6), 592 | ) => { 593 | loc->Location.format->errorGroup(x) 594 | log(l1 ++ ":", x1) 595 | log(l2 ++ ":", x2) 596 | log(l3 ++ ":", x3) 597 | log(l4 ++ ":", x4) 598 | log(l5 ++ ":", x5) 599 | log(l6 ++ ":", x6) 600 | groupEnd() 601 | } 602 | 603 | let error7 = ( 604 | loc: Location.t, 605 | x: 'x, 606 | (l1, x1): (string, 'x1), 607 | (l2, x2): (string, 'x2), 608 | (l3, x3): (string, 'x3), 609 | (l4, x4): (string, 'x4), 610 | (l5, x5): (string, 'x5), 611 | (l6, x6): (string, 'x6), 612 | (l7, x7): (string, 'x7), 613 | ) => { 614 | loc->Location.format->errorGroup(x) 615 | log(l1 ++ ":", x1) 616 | log(l2 ++ ":", x2) 617 | log(l3 ++ ":", x3) 618 | log(l4 ++ ":", x4) 619 | log(l5 ++ ":", x5) 620 | log(l6 ++ ":", x6) 621 | log(l7 ++ ":", x7) 622 | groupEnd() 623 | } 624 | -------------------------------------------------------------------------------- /lib/src/loggers/Browser.resi: -------------------------------------------------------------------------------- 1 | include Interface.Logger 2 | -------------------------------------------------------------------------------- /lib/src/loggers/Edge.res: -------------------------------------------------------------------------------- 1 | @val @scope("console") external log: ('a, 'b) => unit = "log" 2 | @val @scope("console") external group: ('a, 'b, 'c) => unit = "log" 3 | @val @scope("console") external groupCollapsed: ('a, 'b, 'c) => unit = "log" 4 | 5 | // Level: Trace 6 | let traceLabel = `\u001B[48;2;99;99;99m\u001B[38;2;255;255;255m TRACE \u001B[39m\u001B[49m` 7 | 8 | let trace = (loc: Location.t, x: 'x) => { 9 | traceLabel->groupCollapsed(loc->Location.format, x) 10 | } 11 | 12 | let trace1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 13 | traceLabel->group(loc->Location.format, x) 14 | log(l1 ++ ":", x1) 15 | } 16 | 17 | let trace2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 18 | traceLabel->group(loc->Location.format, x) 19 | log(l1 ++ ":", x1) 20 | log(l2 ++ ":", x2) 21 | } 22 | 23 | let trace3 = ( 24 | loc: Location.t, 25 | x: 'x, 26 | (l1, x1): (string, 'x1), 27 | (l2, x2): (string, 'x2), 28 | (l3, x3): (string, 'x3), 29 | ) => { 30 | traceLabel->group(loc->Location.format, x) 31 | log(l1 ++ ":", x1) 32 | log(l2 ++ ":", x2) 33 | log(l3 ++ ":", x3) 34 | } 35 | 36 | let trace4 = ( 37 | loc: Location.t, 38 | x: 'x, 39 | (l1, x1): (string, 'x1), 40 | (l2, x2): (string, 'x2), 41 | (l3, x3): (string, 'x3), 42 | (l4, x4): (string, 'x4), 43 | ) => { 44 | traceLabel->group(loc->Location.format, x) 45 | log(l1 ++ ":", x1) 46 | log(l2 ++ ":", x2) 47 | log(l3 ++ ":", x3) 48 | log(l4 ++ ":", x4) 49 | } 50 | 51 | let trace5 = ( 52 | loc: Location.t, 53 | x: 'x, 54 | (l1, x1): (string, 'x1), 55 | (l2, x2): (string, 'x2), 56 | (l3, x3): (string, 'x3), 57 | (l4, x4): (string, 'x4), 58 | (l5, x5): (string, 'x5), 59 | ) => { 60 | traceLabel->group(loc->Location.format, x) 61 | log(l1 ++ ":", x1) 62 | log(l2 ++ ":", x2) 63 | log(l3 ++ ":", x3) 64 | log(l4 ++ ":", x4) 65 | log(l5 ++ ":", x5) 66 | } 67 | 68 | let trace6 = ( 69 | loc: Location.t, 70 | x: 'x, 71 | (l1, x1): (string, 'x1), 72 | (l2, x2): (string, 'x2), 73 | (l3, x3): (string, 'x3), 74 | (l4, x4): (string, 'x4), 75 | (l5, x5): (string, 'x5), 76 | (l6, x6): (string, 'x6), 77 | ) => { 78 | traceLabel->group(loc->Location.format, x) 79 | log(l1 ++ ":", x1) 80 | log(l2 ++ ":", x2) 81 | log(l3 ++ ":", x3) 82 | log(l4 ++ ":", x4) 83 | log(l5 ++ ":", x5) 84 | log(l6 ++ ":", x6) 85 | } 86 | 87 | let trace7 = ( 88 | loc: Location.t, 89 | x: 'x, 90 | (l1, x1): (string, 'x1), 91 | (l2, x2): (string, 'x2), 92 | (l3, x3): (string, 'x3), 93 | (l4, x4): (string, 'x4), 94 | (l5, x5): (string, 'x5), 95 | (l6, x6): (string, 'x6), 96 | (l7, x7): (string, 'x7), 97 | ) => { 98 | traceLabel->group(loc->Location.format, x) 99 | log(l1 ++ ":", x1) 100 | log(l2 ++ ":", x2) 101 | log(l3 ++ ":", x3) 102 | log(l4 ++ ":", x4) 103 | log(l5 ++ ":", x5) 104 | log(l6 ++ ":", x6) 105 | log(l7 ++ ":", x7) 106 | } 107 | 108 | // Level: Debug 109 | let debugLabel = `\u001B[48;2;130;101;140m\u001B[38;2;255;255;255m DEBUG \u001B[39m\u001B[49m` 110 | 111 | let debug = (loc: Location.t, x: 'x) => { 112 | debugLabel->groupCollapsed(loc->Location.format, x) 113 | } 114 | 115 | let debug1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 116 | debugLabel->group(loc->Location.format, x) 117 | log(l1 ++ ":", x1) 118 | } 119 | 120 | let debug2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 121 | debugLabel->group(loc->Location.format, x) 122 | log(l1 ++ ":", x1) 123 | log(l2 ++ ":", x2) 124 | } 125 | 126 | let debug3 = ( 127 | loc: Location.t, 128 | x: 'x, 129 | (l1, x1): (string, 'x1), 130 | (l2, x2): (string, 'x2), 131 | (l3, x3): (string, 'x3), 132 | ) => { 133 | debugLabel->group(loc->Location.format, x) 134 | log(l1 ++ ":", x1) 135 | log(l2 ++ ":", x2) 136 | log(l3 ++ ":", x3) 137 | } 138 | 139 | let debug4 = ( 140 | loc: Location.t, 141 | x: 'x, 142 | (l1, x1): (string, 'x1), 143 | (l2, x2): (string, 'x2), 144 | (l3, x3): (string, 'x3), 145 | (l4, x4): (string, 'x4), 146 | ) => { 147 | debugLabel->group(loc->Location.format, x) 148 | log(l1 ++ ":", x1) 149 | log(l2 ++ ":", x2) 150 | log(l3 ++ ":", x3) 151 | log(l4 ++ ":", x4) 152 | } 153 | 154 | let debug5 = ( 155 | loc: Location.t, 156 | x: 'x, 157 | (l1, x1): (string, 'x1), 158 | (l2, x2): (string, 'x2), 159 | (l3, x3): (string, 'x3), 160 | (l4, x4): (string, 'x4), 161 | (l5, x5): (string, 'x5), 162 | ) => { 163 | debugLabel->group(loc->Location.format, x) 164 | log(l1 ++ ":", x1) 165 | log(l2 ++ ":", x2) 166 | log(l3 ++ ":", x3) 167 | log(l4 ++ ":", x4) 168 | log(l5 ++ ":", x5) 169 | } 170 | 171 | let debug6 = ( 172 | loc: Location.t, 173 | x: 'x, 174 | (l1, x1): (string, 'x1), 175 | (l2, x2): (string, 'x2), 176 | (l3, x3): (string, 'x3), 177 | (l4, x4): (string, 'x4), 178 | (l5, x5): (string, 'x5), 179 | (l6, x6): (string, 'x6), 180 | ) => { 181 | debugLabel->group(loc->Location.format, x) 182 | log(l1 ++ ":", x1) 183 | log(l2 ++ ":", x2) 184 | log(l3 ++ ":", x3) 185 | log(l4 ++ ":", x4) 186 | log(l5 ++ ":", x5) 187 | log(l6 ++ ":", x6) 188 | } 189 | 190 | let debug7 = ( 191 | loc: Location.t, 192 | x: 'x, 193 | (l1, x1): (string, 'x1), 194 | (l2, x2): (string, 'x2), 195 | (l3, x3): (string, 'x3), 196 | (l4, x4): (string, 'x4), 197 | (l5, x5): (string, 'x5), 198 | (l6, x6): (string, 'x6), 199 | (l7, x7): (string, 'x7), 200 | ) => { 201 | debugLabel->group(loc->Location.format, x) 202 | log(l1 ++ ":", x1) 203 | log(l2 ++ ":", x2) 204 | log(l3 ++ ":", x3) 205 | log(l4 ++ ":", x4) 206 | log(l5 ++ ":", x5) 207 | log(l6 ++ ":", x6) 208 | log(l7 ++ ":", x7) 209 | } 210 | 211 | // Level: Info 212 | let infoLabel = `\u001B[48;2;34;153;221m\u001B[38;2;255;255;255m INFO \u001B[39m\u001B[49m` 213 | 214 | let info = (loc: Location.t, x: 'x) => { 215 | infoLabel->groupCollapsed(loc->Location.format, x) 216 | } 217 | 218 | let info1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 219 | infoLabel->group(loc->Location.format, x) 220 | log(l1 ++ ":", x1) 221 | } 222 | 223 | let info2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 224 | infoLabel->group(loc->Location.format, x) 225 | log(l1 ++ ":", x1) 226 | log(l2 ++ ":", x2) 227 | } 228 | 229 | let info3 = ( 230 | loc: Location.t, 231 | x: 'x, 232 | (l1, x1): (string, 'x1), 233 | (l2, x2): (string, 'x2), 234 | (l3, x3): (string, 'x3), 235 | ) => { 236 | infoLabel->group(loc->Location.format, x) 237 | log(l1 ++ ":", x1) 238 | log(l2 ++ ":", x2) 239 | log(l3 ++ ":", x3) 240 | } 241 | 242 | let info4 = ( 243 | loc: Location.t, 244 | x: 'x, 245 | (l1, x1): (string, 'x1), 246 | (l2, x2): (string, 'x2), 247 | (l3, x3): (string, 'x3), 248 | (l4, x4): (string, 'x4), 249 | ) => { 250 | infoLabel->group(loc->Location.format, x) 251 | log(l1 ++ ":", x1) 252 | log(l2 ++ ":", x2) 253 | log(l3 ++ ":", x3) 254 | log(l4 ++ ":", x4) 255 | } 256 | 257 | let info5 = ( 258 | loc: Location.t, 259 | x: 'x, 260 | (l1, x1): (string, 'x1), 261 | (l2, x2): (string, 'x2), 262 | (l3, x3): (string, 'x3), 263 | (l4, x4): (string, 'x4), 264 | (l5, x5): (string, 'x5), 265 | ) => { 266 | infoLabel->group(loc->Location.format, x) 267 | log(l1 ++ ":", x1) 268 | log(l2 ++ ":", x2) 269 | log(l3 ++ ":", x3) 270 | log(l4 ++ ":", x4) 271 | log(l5 ++ ":", x5) 272 | } 273 | 274 | let info6 = ( 275 | loc: Location.t, 276 | x: 'x, 277 | (l1, x1): (string, 'x1), 278 | (l2, x2): (string, 'x2), 279 | (l3, x3): (string, 'x3), 280 | (l4, x4): (string, 'x4), 281 | (l5, x5): (string, 'x5), 282 | (l6, x6): (string, 'x6), 283 | ) => { 284 | infoLabel->group(loc->Location.format, x) 285 | log(l1 ++ ":", x1) 286 | log(l2 ++ ":", x2) 287 | log(l3 ++ ":", x3) 288 | log(l4 ++ ":", x4) 289 | log(l5 ++ ":", x5) 290 | log(l6 ++ ":", x6) 291 | } 292 | 293 | let info7 = ( 294 | loc: Location.t, 295 | x: 'x, 296 | (l1, x1): (string, 'x1), 297 | (l2, x2): (string, 'x2), 298 | (l3, x3): (string, 'x3), 299 | (l4, x4): (string, 'x4), 300 | (l5, x5): (string, 'x5), 301 | (l6, x6): (string, 'x6), 302 | (l7, x7): (string, 'x7), 303 | ) => { 304 | infoLabel->group(loc->Location.format, x) 305 | log(l1 ++ ":", x1) 306 | log(l2 ++ ":", x2) 307 | log(l3 ++ ":", x3) 308 | log(l4 ++ ":", x4) 309 | log(l5 ++ ":", x5) 310 | log(l6 ++ ":", x6) 311 | log(l7 ++ ":", x7) 312 | } 313 | 314 | // Level: Warn 315 | let warnLabel = `\u001B[48;2;252;228;115m\u001B[38;2;87;58;8m WARNING \u001B[39m\u001B[49m` 316 | 317 | let warn = (loc: Location.t, x: 'x) => { 318 | warnLabel->groupCollapsed(loc->Location.format, x) 319 | } 320 | 321 | let warn1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 322 | warnLabel->group(loc->Location.format, x) 323 | log(l1 ++ ":", x1) 324 | } 325 | 326 | let warn2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 327 | warnLabel->group(loc->Location.format, x) 328 | log(l1 ++ ":", x1) 329 | log(l2 ++ ":", x2) 330 | } 331 | 332 | let warn3 = ( 333 | loc: Location.t, 334 | x: 'x, 335 | (l1, x1): (string, 'x1), 336 | (l2, x2): (string, 'x2), 337 | (l3, x3): (string, 'x3), 338 | ) => { 339 | warnLabel->group(loc->Location.format, x) 340 | log(l1 ++ ":", x1) 341 | log(l2 ++ ":", x2) 342 | log(l3 ++ ":", x3) 343 | } 344 | 345 | let warn4 = ( 346 | loc: Location.t, 347 | x: 'x, 348 | (l1, x1): (string, 'x1), 349 | (l2, x2): (string, 'x2), 350 | (l3, x3): (string, 'x3), 351 | (l4, x4): (string, 'x4), 352 | ) => { 353 | warnLabel->group(loc->Location.format, x) 354 | log(l1 ++ ":", x1) 355 | log(l2 ++ ":", x2) 356 | log(l3 ++ ":", x3) 357 | log(l4 ++ ":", x4) 358 | } 359 | 360 | let warn5 = ( 361 | loc: Location.t, 362 | x: 'x, 363 | (l1, x1): (string, 'x1), 364 | (l2, x2): (string, 'x2), 365 | (l3, x3): (string, 'x3), 366 | (l4, x4): (string, 'x5), 367 | (l5, x5): (string, 'x6), 368 | ) => { 369 | warnLabel->group(loc->Location.format, x) 370 | log(l1 ++ ":", x1) 371 | log(l2 ++ ":", x2) 372 | log(l3 ++ ":", x3) 373 | log(l4 ++ ":", x4) 374 | log(l5 ++ ":", x5) 375 | } 376 | 377 | let warn6 = ( 378 | loc: Location.t, 379 | x: 'x, 380 | (l1, x1): (string, 'x1), 381 | (l2, x2): (string, 'x2), 382 | (l3, x3): (string, 'x3), 383 | (l4, x4): (string, 'x4), 384 | (l5, x5): (string, 'x5), 385 | (l6, x6): (string, 'x6), 386 | ) => { 387 | warnLabel->group(loc->Location.format, x) 388 | log(l1 ++ ":", x1) 389 | log(l2 ++ ":", x2) 390 | log(l3 ++ ":", x3) 391 | log(l4 ++ ":", x4) 392 | log(l5 ++ ":", x5) 393 | log(l6 ++ ":", x6) 394 | } 395 | 396 | let warn7 = ( 397 | loc: Location.t, 398 | x: 'x, 399 | (l1, x1): (string, 'x1), 400 | (l2, x2): (string, 'x2), 401 | (l3, x3): (string, 'x3), 402 | (l4, x4): (string, 'x4), 403 | (l5, x5): (string, 'x5), 404 | (l6, x6): (string, 'x6), 405 | (l7, x7): (string, 'x7), 406 | ) => { 407 | warnLabel->group(loc->Location.format, x) 408 | log(l1 ++ ":", x1) 409 | log(l2 ++ ":", x2) 410 | log(l3 ++ ":", x3) 411 | log(l4 ++ ":", x4) 412 | log(l5 ++ ":", x5) 413 | log(l6 ++ ":", x6) 414 | log(l7 ++ ":", x7) 415 | } 416 | 417 | // Level: Error 418 | let errorLabel = `\u001B[48;2;209;26;26m\u001B[38;2;255;255;255m ERROR \u001B[39m\u001B[49m` 419 | 420 | let error = (loc: Location.t, x: 'x) => { 421 | errorLabel->groupCollapsed(loc->Location.format, x) 422 | } 423 | 424 | let error1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 425 | errorLabel->group(loc->Location.format, x) 426 | log(l1 ++ ":", x1) 427 | } 428 | 429 | let error2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 430 | errorLabel->group(loc->Location.format, x) 431 | log(l1 ++ ":", x1) 432 | log(l2 ++ ":", x2) 433 | } 434 | 435 | let error3 = ( 436 | loc: Location.t, 437 | x: 'x, 438 | (l1, x1): (string, 'x1), 439 | (l2, x2): (string, 'x2), 440 | (l3, x3): (string, 'x3), 441 | ) => { 442 | errorLabel->group(loc->Location.format, x) 443 | log(l1 ++ ":", x1) 444 | log(l2 ++ ":", x2) 445 | log(l3 ++ ":", x3) 446 | } 447 | 448 | let error4 = ( 449 | loc: Location.t, 450 | x: 'x, 451 | (l1, x1): (string, 'x1), 452 | (l2, x2): (string, 'x2), 453 | (l3, x3): (string, 'x3), 454 | (l4, x4): (string, 'x4), 455 | ) => { 456 | errorLabel->group(loc->Location.format, x) 457 | log(l1 ++ ":", x1) 458 | log(l2 ++ ":", x2) 459 | log(l3 ++ ":", x3) 460 | log(l4 ++ ":", x4) 461 | } 462 | 463 | let error5 = ( 464 | loc: Location.t, 465 | x: 'x, 466 | (l1, x1): (string, 'x1), 467 | (l2, x2): (string, 'x2), 468 | (l3, x3): (string, 'x3), 469 | (l4, x4): (string, 'x4), 470 | (l5, x5): (string, 'x5), 471 | ) => { 472 | errorLabel->group(loc->Location.format, x) 473 | log(l1 ++ ":", x1) 474 | log(l2 ++ ":", x2) 475 | log(l3 ++ ":", x3) 476 | log(l4 ++ ":", x4) 477 | log(l5 ++ ":", x5) 478 | } 479 | 480 | let error6 = ( 481 | loc: Location.t, 482 | x: 'x, 483 | (l1, x1): (string, 'x1), 484 | (l2, x2): (string, 'x2), 485 | (l3, x3): (string, 'x3), 486 | (l4, x4): (string, 'x4), 487 | (l5, x5): (string, 'x5), 488 | (l6, x6): (string, 'x6), 489 | ) => { 490 | errorLabel->group(loc->Location.format, x) 491 | log(l1 ++ ":", x1) 492 | log(l2 ++ ":", x2) 493 | log(l3 ++ ":", x3) 494 | log(l4 ++ ":", x4) 495 | log(l5 ++ ":", x5) 496 | log(l6 ++ ":", x6) 497 | } 498 | 499 | let error7 = ( 500 | loc: Location.t, 501 | x: 'x, 502 | (l1, x1): (string, 'x1), 503 | (l2, x2): (string, 'x2), 504 | (l3, x3): (string, 'x3), 505 | (l4, x4): (string, 'x4), 506 | (l5, x5): (string, 'x5), 507 | (l6, x6): (string, 'x6), 508 | (l7, x7): (string, 'x7), 509 | ) => { 510 | errorLabel->group(loc->Location.format, x) 511 | log(l1 ++ ":", x1) 512 | log(l2 ++ ":", x2) 513 | log(l3 ++ ":", x3) 514 | log(l4 ++ ":", x4) 515 | log(l5 ++ ":", x5) 516 | log(l6 ++ ":", x6) 517 | log(l7 ++ ":", x7) 518 | } 519 | -------------------------------------------------------------------------------- /lib/src/loggers/Edge.resi: -------------------------------------------------------------------------------- 1 | include Interface.Logger 2 | -------------------------------------------------------------------------------- /lib/src/loggers/Node.res: -------------------------------------------------------------------------------- 1 | @val @scope("console") external log: ('a, 'b) => unit = "log" 2 | @val @scope("console") external group: ('a, 'b, 'c) => unit = "group" 3 | @val @scope("console") external groupCollapsed: ('a, 'b, 'c) => unit = "groupCollapsed" 4 | @val @scope("console") external groupEnd: unit => unit = "groupEnd" 5 | 6 | // Level: Trace 7 | let traceLabel = `\u001B[48;2;99;99;99m\u001B[38;2;255;255;255m TRACE \u001B[39m\u001B[49m` 8 | 9 | let trace = (loc: Location.t, x: 'x) => { 10 | traceLabel->groupCollapsed(loc->Location.format, x) 11 | groupEnd() 12 | } 13 | 14 | let trace1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 15 | traceLabel->group(loc->Location.format, x) 16 | log(l1 ++ ":", x1) 17 | groupEnd() 18 | } 19 | 20 | let trace2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 21 | traceLabel->group(loc->Location.format, x) 22 | log(l1 ++ ":", x1) 23 | log(l2 ++ ":", x2) 24 | groupEnd() 25 | } 26 | 27 | let trace3 = ( 28 | loc: Location.t, 29 | x: 'x, 30 | (l1, x1): (string, 'x1), 31 | (l2, x2): (string, 'x2), 32 | (l3, x3): (string, 'x3), 33 | ) => { 34 | traceLabel->group(loc->Location.format, x) 35 | log(l1 ++ ":", x1) 36 | log(l2 ++ ":", x2) 37 | log(l3 ++ ":", x3) 38 | groupEnd() 39 | } 40 | 41 | let trace4 = ( 42 | loc: Location.t, 43 | x: 'x, 44 | (l1, x1): (string, 'x1), 45 | (l2, x2): (string, 'x2), 46 | (l3, x3): (string, 'x3), 47 | (l4, x4): (string, 'x4), 48 | ) => { 49 | traceLabel->group(loc->Location.format, x) 50 | log(l1 ++ ":", x1) 51 | log(l2 ++ ":", x2) 52 | log(l3 ++ ":", x3) 53 | log(l4 ++ ":", x4) 54 | groupEnd() 55 | } 56 | 57 | let trace5 = ( 58 | loc: Location.t, 59 | x: 'x, 60 | (l1, x1): (string, 'x1), 61 | (l2, x2): (string, 'x2), 62 | (l3, x3): (string, 'x3), 63 | (l4, x4): (string, 'x4), 64 | (l5, x5): (string, 'x5), 65 | ) => { 66 | traceLabel->group(loc->Location.format, x) 67 | log(l1 ++ ":", x1) 68 | log(l2 ++ ":", x2) 69 | log(l3 ++ ":", x3) 70 | log(l4 ++ ":", x4) 71 | log(l5 ++ ":", x5) 72 | groupEnd() 73 | } 74 | 75 | let trace6 = ( 76 | loc: Location.t, 77 | x: 'x, 78 | (l1, x1): (string, 'x1), 79 | (l2, x2): (string, 'x2), 80 | (l3, x3): (string, 'x3), 81 | (l4, x4): (string, 'x4), 82 | (l5, x5): (string, 'x5), 83 | (l6, x6): (string, 'x6), 84 | ) => { 85 | traceLabel->group(loc->Location.format, x) 86 | log(l1 ++ ":", x1) 87 | log(l2 ++ ":", x2) 88 | log(l3 ++ ":", x3) 89 | log(l4 ++ ":", x4) 90 | log(l5 ++ ":", x5) 91 | log(l6 ++ ":", x6) 92 | groupEnd() 93 | } 94 | 95 | let trace7 = ( 96 | loc: Location.t, 97 | x: 'x, 98 | (l1, x1): (string, 'x1), 99 | (l2, x2): (string, 'x2), 100 | (l3, x3): (string, 'x3), 101 | (l4, x4): (string, 'x4), 102 | (l5, x5): (string, 'x5), 103 | (l6, x6): (string, 'x6), 104 | (l7, x7): (string, 'x7), 105 | ) => { 106 | traceLabel->group(loc->Location.format, x) 107 | log(l1 ++ ":", x1) 108 | log(l2 ++ ":", x2) 109 | log(l3 ++ ":", x3) 110 | log(l4 ++ ":", x4) 111 | log(l5 ++ ":", x5) 112 | log(l6 ++ ":", x6) 113 | log(l7 ++ ":", x7) 114 | groupEnd() 115 | } 116 | 117 | // Level: Debug 118 | let debugLabel = `\u001B[48;2;130;101;140m\u001B[38;2;255;255;255m DEBUG \u001B[39m\u001B[49m` 119 | 120 | let debug = (loc: Location.t, x: 'x) => { 121 | debugLabel->groupCollapsed(loc->Location.format, x) 122 | groupEnd() 123 | } 124 | 125 | let debug1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 126 | debugLabel->group(loc->Location.format, x) 127 | log(l1 ++ ":", x1) 128 | groupEnd() 129 | } 130 | 131 | let debug2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 132 | debugLabel->group(loc->Location.format, x) 133 | log(l1 ++ ":", x1) 134 | log(l2 ++ ":", x2) 135 | groupEnd() 136 | } 137 | 138 | let debug3 = ( 139 | loc: Location.t, 140 | x: 'x, 141 | (l1, x1): (string, 'x1), 142 | (l2, x2): (string, 'x2), 143 | (l3, x3): (string, 'x3), 144 | ) => { 145 | debugLabel->group(loc->Location.format, x) 146 | log(l1 ++ ":", x1) 147 | log(l2 ++ ":", x2) 148 | log(l3 ++ ":", x3) 149 | groupEnd() 150 | } 151 | 152 | let debug4 = ( 153 | loc: Location.t, 154 | x: 'x, 155 | (l1, x1): (string, 'x1), 156 | (l2, x2): (string, 'x2), 157 | (l3, x3): (string, 'x3), 158 | (l4, x4): (string, 'x4), 159 | ) => { 160 | debugLabel->group(loc->Location.format, x) 161 | log(l1 ++ ":", x1) 162 | log(l2 ++ ":", x2) 163 | log(l3 ++ ":", x3) 164 | log(l4 ++ ":", x4) 165 | groupEnd() 166 | } 167 | 168 | let debug5 = ( 169 | loc: Location.t, 170 | x: 'x, 171 | (l1, x1): (string, 'x1), 172 | (l2, x2): (string, 'x2), 173 | (l3, x3): (string, 'x3), 174 | (l4, x4): (string, 'x4), 175 | (l5, x5): (string, 'x5), 176 | ) => { 177 | debugLabel->group(loc->Location.format, x) 178 | log(l1 ++ ":", x1) 179 | log(l2 ++ ":", x2) 180 | log(l3 ++ ":", x3) 181 | log(l4 ++ ":", x4) 182 | log(l5 ++ ":", x5) 183 | groupEnd() 184 | } 185 | 186 | let debug6 = ( 187 | loc: Location.t, 188 | x: 'x, 189 | (l1, x1): (string, 'x1), 190 | (l2, x2): (string, 'x2), 191 | (l3, x3): (string, 'x3), 192 | (l4, x4): (string, 'x4), 193 | (l5, x5): (string, 'x5), 194 | (l6, x6): (string, 'x6), 195 | ) => { 196 | debugLabel->group(loc->Location.format, x) 197 | log(l1 ++ ":", x1) 198 | log(l2 ++ ":", x2) 199 | log(l3 ++ ":", x3) 200 | log(l4 ++ ":", x4) 201 | log(l5 ++ ":", x5) 202 | log(l6 ++ ":", x6) 203 | groupEnd() 204 | } 205 | 206 | let debug7 = ( 207 | loc: Location.t, 208 | x: 'x, 209 | (l1, x1): (string, 'x1), 210 | (l2, x2): (string, 'x2), 211 | (l3, x3): (string, 'x3), 212 | (l4, x4): (string, 'x4), 213 | (l5, x5): (string, 'x5), 214 | (l6, x6): (string, 'x6), 215 | (l7, x7): (string, 'x7), 216 | ) => { 217 | debugLabel->group(loc->Location.format, x) 218 | log(l1 ++ ":", x1) 219 | log(l2 ++ ":", x2) 220 | log(l3 ++ ":", x3) 221 | log(l4 ++ ":", x4) 222 | log(l5 ++ ":", x5) 223 | log(l6 ++ ":", x6) 224 | log(l7 ++ ":", x7) 225 | groupEnd() 226 | } 227 | 228 | // Level: Info 229 | let infoLabel = `\u001B[48;2;34;153;221m\u001B[38;2;255;255;255m INFO \u001B[39m\u001B[49m` 230 | 231 | let info = (loc: Location.t, x: 'x) => { 232 | infoLabel->groupCollapsed(loc->Location.format, x) 233 | groupEnd() 234 | } 235 | 236 | let info1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 237 | infoLabel->group(loc->Location.format, x) 238 | log(l1 ++ ":", x1) 239 | groupEnd() 240 | } 241 | 242 | let info2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 243 | infoLabel->group(loc->Location.format, x) 244 | log(l1 ++ ":", x1) 245 | log(l2 ++ ":", x2) 246 | groupEnd() 247 | } 248 | 249 | let info3 = ( 250 | loc: Location.t, 251 | x: 'x, 252 | (l1, x1): (string, 'x1), 253 | (l2, x2): (string, 'x2), 254 | (l3, x3): (string, 'x3), 255 | ) => { 256 | infoLabel->group(loc->Location.format, x) 257 | log(l1 ++ ":", x1) 258 | log(l2 ++ ":", x2) 259 | log(l3 ++ ":", x3) 260 | groupEnd() 261 | } 262 | 263 | let info4 = ( 264 | loc: Location.t, 265 | x: 'x, 266 | (l1, x1): (string, 'x1), 267 | (l2, x2): (string, 'x2), 268 | (l3, x3): (string, 'x3), 269 | (l4, x4): (string, 'x4), 270 | ) => { 271 | infoLabel->group(loc->Location.format, x) 272 | log(l1 ++ ":", x1) 273 | log(l2 ++ ":", x2) 274 | log(l3 ++ ":", x3) 275 | log(l4 ++ ":", x4) 276 | groupEnd() 277 | } 278 | 279 | let info5 = ( 280 | loc: Location.t, 281 | x: 'x, 282 | (l1, x1): (string, 'x1), 283 | (l2, x2): (string, 'x2), 284 | (l3, x3): (string, 'x3), 285 | (l4, x4): (string, 'x4), 286 | (l5, x5): (string, 'x5), 287 | ) => { 288 | infoLabel->group(loc->Location.format, x) 289 | log(l1 ++ ":", x1) 290 | log(l2 ++ ":", x2) 291 | log(l3 ++ ":", x3) 292 | log(l4 ++ ":", x4) 293 | log(l5 ++ ":", x5) 294 | groupEnd() 295 | } 296 | 297 | let info6 = ( 298 | loc: Location.t, 299 | x: 'x, 300 | (l1, x1): (string, 'x1), 301 | (l2, x2): (string, 'x2), 302 | (l3, x3): (string, 'x3), 303 | (l4, x4): (string, 'x4), 304 | (l5, x5): (string, 'x5), 305 | (l6, x6): (string, 'x6), 306 | ) => { 307 | infoLabel->group(loc->Location.format, x) 308 | log(l1 ++ ":", x1) 309 | log(l2 ++ ":", x2) 310 | log(l3 ++ ":", x3) 311 | log(l4 ++ ":", x4) 312 | log(l5 ++ ":", x5) 313 | log(l6 ++ ":", x6) 314 | groupEnd() 315 | } 316 | 317 | let info7 = ( 318 | loc: Location.t, 319 | x: 'x, 320 | (l1, x1): (string, 'x1), 321 | (l2, x2): (string, 'x2), 322 | (l3, x3): (string, 'x3), 323 | (l4, x4): (string, 'x4), 324 | (l5, x5): (string, 'x5), 325 | (l6, x6): (string, 'x6), 326 | (l7, x7): (string, 'x7), 327 | ) => { 328 | infoLabel->group(loc->Location.format, x) 329 | log(l1 ++ ":", x1) 330 | log(l2 ++ ":", x2) 331 | log(l3 ++ ":", x3) 332 | log(l4 ++ ":", x4) 333 | log(l5 ++ ":", x5) 334 | log(l6 ++ ":", x6) 335 | log(l7 ++ ":", x7) 336 | groupEnd() 337 | } 338 | 339 | // Level: Warn 340 | let warnLabel = `\u001B[48;2;252;228;115m\u001B[38;2;87;58;8m WARNING \u001B[39m\u001B[49m` 341 | 342 | let warn = (loc: Location.t, x: 'x) => { 343 | warnLabel->groupCollapsed(loc->Location.format, x) 344 | groupEnd() 345 | } 346 | 347 | let warn1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 348 | warnLabel->group(loc->Location.format, x) 349 | log(l1 ++ ":", x1) 350 | groupEnd() 351 | } 352 | 353 | let warn2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 354 | warnLabel->group(loc->Location.format, x) 355 | log(l1 ++ ":", x1) 356 | log(l2 ++ ":", x2) 357 | groupEnd() 358 | } 359 | 360 | let warn3 = ( 361 | loc: Location.t, 362 | x: 'x, 363 | (l1, x1): (string, 'x1), 364 | (l2, x2): (string, 'x2), 365 | (l3, x3): (string, 'x3), 366 | ) => { 367 | warnLabel->group(loc->Location.format, x) 368 | log(l1 ++ ":", x1) 369 | log(l2 ++ ":", x2) 370 | log(l3 ++ ":", x3) 371 | groupEnd() 372 | } 373 | 374 | let warn4 = ( 375 | loc: Location.t, 376 | x: 'x, 377 | (l1, x1): (string, 'x1), 378 | (l2, x2): (string, 'x2), 379 | (l3, x3): (string, 'x3), 380 | (l4, x4): (string, 'x4), 381 | ) => { 382 | warnLabel->group(loc->Location.format, x) 383 | log(l1 ++ ":", x1) 384 | log(l2 ++ ":", x2) 385 | log(l3 ++ ":", x3) 386 | log(l4 ++ ":", x4) 387 | groupEnd() 388 | } 389 | 390 | let warn5 = ( 391 | loc: Location.t, 392 | x: 'x, 393 | (l1, x1): (string, 'x1), 394 | (l2, x2): (string, 'x2), 395 | (l3, x3): (string, 'x3), 396 | (l4, x4): (string, 'x5), 397 | (l5, x5): (string, 'x6), 398 | ) => { 399 | warnLabel->group(loc->Location.format, x) 400 | log(l1 ++ ":", x1) 401 | log(l2 ++ ":", x2) 402 | log(l3 ++ ":", x3) 403 | log(l4 ++ ":", x4) 404 | log(l5 ++ ":", x5) 405 | groupEnd() 406 | } 407 | 408 | let warn6 = ( 409 | loc: Location.t, 410 | x: 'x, 411 | (l1, x1): (string, 'x1), 412 | (l2, x2): (string, 'x2), 413 | (l3, x3): (string, 'x3), 414 | (l4, x4): (string, 'x4), 415 | (l5, x5): (string, 'x5), 416 | (l6, x6): (string, 'x6), 417 | ) => { 418 | warnLabel->group(loc->Location.format, x) 419 | log(l1 ++ ":", x1) 420 | log(l2 ++ ":", x2) 421 | log(l3 ++ ":", x3) 422 | log(l4 ++ ":", x4) 423 | log(l5 ++ ":", x5) 424 | log(l6 ++ ":", x6) 425 | groupEnd() 426 | } 427 | 428 | let warn7 = ( 429 | loc: Location.t, 430 | x: 'x, 431 | (l1, x1): (string, 'x1), 432 | (l2, x2): (string, 'x2), 433 | (l3, x3): (string, 'x3), 434 | (l4, x4): (string, 'x4), 435 | (l5, x5): (string, 'x5), 436 | (l6, x6): (string, 'x6), 437 | (l7, x7): (string, 'x7), 438 | ) => { 439 | warnLabel->group(loc->Location.format, x) 440 | log(l1 ++ ":", x1) 441 | log(l2 ++ ":", x2) 442 | log(l3 ++ ":", x3) 443 | log(l4 ++ ":", x4) 444 | log(l5 ++ ":", x5) 445 | log(l6 ++ ":", x6) 446 | log(l7 ++ ":", x7) 447 | groupEnd() 448 | } 449 | 450 | // Level: Error 451 | let errorLabel = `\u001B[48;2;209;26;26m\u001B[38;2;255;255;255m ERROR \u001B[39m\u001B[49m` 452 | 453 | let error = (loc: Location.t, x: 'x) => { 454 | errorLabel->groupCollapsed(loc->Location.format, x) 455 | groupEnd() 456 | } 457 | 458 | let error1 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1)) => { 459 | errorLabel->group(loc->Location.format, x) 460 | log(l1 ++ ":", x1) 461 | groupEnd() 462 | } 463 | 464 | let error2 = (loc: Location.t, x: 'x, (l1, x1): (string, 'x1), (l2, x2): (string, 'x2)) => { 465 | errorLabel->group(loc->Location.format, x) 466 | log(l1 ++ ":", x1) 467 | log(l2 ++ ":", x2) 468 | groupEnd() 469 | } 470 | 471 | let error3 = ( 472 | loc: Location.t, 473 | x: 'x, 474 | (l1, x1): (string, 'x1), 475 | (l2, x2): (string, 'x2), 476 | (l3, x3): (string, 'x3), 477 | ) => { 478 | errorLabel->group(loc->Location.format, x) 479 | log(l1 ++ ":", x1) 480 | log(l2 ++ ":", x2) 481 | log(l3 ++ ":", x3) 482 | groupEnd() 483 | } 484 | 485 | let error4 = ( 486 | loc: Location.t, 487 | x: 'x, 488 | (l1, x1): (string, 'x1), 489 | (l2, x2): (string, 'x2), 490 | (l3, x3): (string, 'x3), 491 | (l4, x4): (string, 'x4), 492 | ) => { 493 | errorLabel->group(loc->Location.format, x) 494 | log(l1 ++ ":", x1) 495 | log(l2 ++ ":", x2) 496 | log(l3 ++ ":", x3) 497 | log(l4 ++ ":", x4) 498 | groupEnd() 499 | } 500 | 501 | let error5 = ( 502 | loc: Location.t, 503 | x: 'x, 504 | (l1, x1): (string, 'x1), 505 | (l2, x2): (string, 'x2), 506 | (l3, x3): (string, 'x3), 507 | (l4, x4): (string, 'x4), 508 | (l5, x5): (string, 'x5), 509 | ) => { 510 | errorLabel->group(loc->Location.format, x) 511 | log(l1 ++ ":", x1) 512 | log(l2 ++ ":", x2) 513 | log(l3 ++ ":", x3) 514 | log(l4 ++ ":", x4) 515 | log(l5 ++ ":", x5) 516 | groupEnd() 517 | } 518 | 519 | let error6 = ( 520 | loc: Location.t, 521 | x: 'x, 522 | (l1, x1): (string, 'x1), 523 | (l2, x2): (string, 'x2), 524 | (l3, x3): (string, 'x3), 525 | (l4, x4): (string, 'x4), 526 | (l5, x5): (string, 'x5), 527 | (l6, x6): (string, 'x6), 528 | ) => { 529 | errorLabel->group(loc->Location.format, x) 530 | log(l1 ++ ":", x1) 531 | log(l2 ++ ":", x2) 532 | log(l3 ++ ":", x3) 533 | log(l4 ++ ":", x4) 534 | log(l5 ++ ":", x5) 535 | log(l6 ++ ":", x6) 536 | groupEnd() 537 | } 538 | 539 | let error7 = ( 540 | loc: Location.t, 541 | x: 'x, 542 | (l1, x1): (string, 'x1), 543 | (l2, x2): (string, 'x2), 544 | (l3, x3): (string, 'x3), 545 | (l4, x4): (string, 'x4), 546 | (l5, x5): (string, 'x5), 547 | (l6, x6): (string, 'x6), 548 | (l7, x7): (string, 'x7), 549 | ) => { 550 | errorLabel->group(loc->Location.format, x) 551 | log(l1 ++ ":", x1) 552 | log(l2 ++ ":", x2) 553 | log(l3 ++ ":", x3) 554 | log(l4 ++ ":", x4) 555 | log(l5 ++ ":", x5) 556 | log(l6 ++ ":", x6) 557 | log(l7 ++ ":", x7) 558 | groupEnd() 559 | } 560 | -------------------------------------------------------------------------------- /lib/src/loggers/Node.resi: -------------------------------------------------------------------------------- 1 | include Interface.Logger 2 | -------------------------------------------------------------------------------- /lib/src/loggers/Universal.res: -------------------------------------------------------------------------------- 1 | @val external window: Dom.window = "window" 2 | 3 | // NOTE: Unfortunately, it pulls in currying. 4 | // Not sure if it's possible to uncurry without changing the interface, which would be a breaking change. 5 | include unpack( 6 | window->Js.typeof == "undefined" 7 | ? module(Node: Interface.Logger) 8 | : module(Browser: Interface.Logger) 9 | ) 10 | -------------------------------------------------------------------------------- /lib/src/loggers/Universal.resi: -------------------------------------------------------------------------------- 1 | include Interface.Logger 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rescript-logger", 3 | "version": "4.0.0", 4 | "description": "Logging implementation for ReScript", 5 | "author": "Alex Fedoseev ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/shakacode/rescript-logger.git" 10 | }, 11 | "private": true, 12 | "workspaces": [ 13 | "lib", 14 | "examples" 15 | ], 16 | "files": [ 17 | "src", 18 | "bin", 19 | "rescript.json", 20 | "postinstall.js" 21 | ], 22 | "keywords": [ 23 | "log", 24 | "logger", 25 | "logging", 26 | "rescript", 27 | "reason", 28 | "reasonml", 29 | "ocaml", 30 | "bucklescript" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /ppx/bin/Bin.ml: -------------------------------------------------------------------------------- 1 | Ppxlib.Driver.run_as_ppx_rewriter () 2 | -------------------------------------------------------------------------------- /ppx/bin/dune: -------------------------------------------------------------------------------- 1 | (env 2 | (static 3 | (flags 4 | (:standard -ccopt -static)))) 5 | 6 | (executable 7 | (package rescript-logger-ppx) 8 | (name bin) 9 | (public_name rescript-logger-ppx) 10 | (libraries rescript-logger-ppx.lib)) 11 | -------------------------------------------------------------------------------- /ppx/lib/Lib.ml: -------------------------------------------------------------------------------- 1 | open Ppxlib 2 | open Ast_helper 3 | 4 | module Env = struct 5 | let level = "RES_LOG" 6 | let logger = "RES_LOGGER" 7 | let only = "RES_LOG_ONLY" 8 | end 9 | 10 | module Delimiter = struct 11 | let key_val = '=' 12 | let entries = ',' 13 | end 14 | 15 | module Level = struct 16 | type t = 17 | | Trace 18 | | Debug 19 | | Info 20 | | Warn 21 | | Error 22 | 23 | let from_string = 24 | function 25 | | "*" 26 | | "trace" -> Some(Trace) 27 | | "debug" -> Some(Debug) 28 | | "info" -> Some(Info) 29 | | "warn" 30 | | "warning" -> Some(Warn) 31 | | "error" -> Some(Error) 32 | | "off" -> None 33 | | _ as x -> failwith ("Invalid log level: " ^ x); 34 | end 35 | 36 | module Fn = struct 37 | type t = 38 | | Trace 39 | | Trace1 40 | | Trace2 41 | | Trace3 42 | | Trace4 43 | | Trace5 44 | | Trace6 45 | | Trace7 46 | | Debug 47 | | Debug1 48 | | Debug2 49 | | Debug3 50 | | Debug4 51 | | Debug5 52 | | Debug6 53 | | Debug7 54 | | Info 55 | | Info1 56 | | Info2 57 | | Info3 58 | | Info4 59 | | Info5 60 | | Info6 61 | | Info7 62 | | Warn 63 | | Warn1 64 | | Warn2 65 | | Warn3 66 | | Warn4 67 | | Warn5 68 | | Warn6 69 | | Warn7 70 | | Error 71 | | Error1 72 | | Error2 73 | | Error3 74 | | Error4 75 | | Error5 76 | | Error6 77 | | Error7 78 | 79 | let to_string = 80 | function 81 | | Trace -> "trace" 82 | | Trace1 -> "trace1" 83 | | Trace2 -> "trace2" 84 | | Trace3 -> "trace3" 85 | | Trace4 -> "trace4" 86 | | Trace5 -> "trace5" 87 | | Trace6 -> "trace6" 88 | | Trace7 -> "trace7" 89 | | Debug -> "debug" 90 | | Debug1 -> "debug1" 91 | | Debug2 -> "debug2" 92 | | Debug3 -> "debug3" 93 | | Debug4 -> "debug4" 94 | | Debug5 -> "debug5" 95 | | Debug6 -> "debug6" 96 | | Debug7 -> "debug7" 97 | | Info -> "info" 98 | | Info1 -> "info1" 99 | | Info2 -> "info2" 100 | | Info3 -> "info3" 101 | | Info4 -> "info4" 102 | | Info5 -> "info5" 103 | | Info6 -> "info6" 104 | | Info7 -> "info7" 105 | | Warn -> "warn" 106 | | Warn1 -> "warn1" 107 | | Warn2 -> "warn2" 108 | | Warn3 -> "warn3" 109 | | Warn4 -> "warn4" 110 | | Warn5 -> "warn5" 111 | | Warn6 -> "warn6" 112 | | Warn7 -> "warn7" 113 | | Error -> "error" 114 | | Error1 -> "error1" 115 | | Error2 -> "error2" 116 | | Error3 -> "error3" 117 | | Error4 -> "error4" 118 | | Error5 -> "error5" 119 | | Error6 -> "error6" 120 | | Error7 -> "error7" 121 | end 122 | 123 | module LibArg = struct 124 | let box: string option ref = ref None 125 | 126 | let set x = box := Some x 127 | let reset () = box := None 128 | 129 | let key = "--lib" 130 | let spec = Arg.String set 131 | let doc = " Library name" 132 | end 133 | 134 | module Lib = struct 135 | let from_args () = 136 | if Sys.argv |> Array.length > 1 137 | then 138 | match Sys.argv.(1) |> String.split_on_char Delimiter.key_val with 139 | | "--lib"::lib::[] -> Some lib 140 | | _ -> None 141 | else 142 | None 143 | end 144 | 145 | let level = 146 | let default = Level.Warn in 147 | let lib = Lib.from_args () in 148 | 149 | match Env.level |> Sys.getenv with 150 | | exception Not_found -> 151 | ( 152 | match lib with 153 | | Some _ -> None 154 | | None -> Some default 155 | ) 156 | | _ as raw_env_entries -> 157 | let entries = raw_env_entries |> String.split_on_char Delimiter.entries in 158 | match (entries, lib) with 159 | | ([], _) -> failwith ("Empty value of environment variable " ^ Env.level) 160 | | ((level::[] | level::_), None) -> level |> Level.from_string 161 | | (entries, Some lib) -> 162 | entries |> 163 | ( 164 | List.fold_left 165 | ( 166 | fun res entry -> 167 | match res with 168 | | Some res -> Some res 169 | | None -> 170 | match entry |> String.split_on_char Delimiter.key_val with 171 | | lib'::level::[] when lib' = lib -> level |> Level.from_string 172 | | _ -> None 173 | ) 174 | None 175 | ) 176 | 177 | let logger = 178 | let default = "ReScriptLogger.Browser" in 179 | 180 | let rec build ?lid xs = 181 | match (lid, xs) with 182 | | (None, x::xs) -> xs |> build ~lid: (Lident x) 183 | | (Some lid, x::xs) -> xs |> build ~lid: (Ldot (lid, x)) 184 | | (Some lid, []) -> lid 185 | | (None, []) -> failwith "Empty logger" in 186 | 187 | let parse x = x |> String.split_on_char '.' |> build in 188 | 189 | match Env.logger |> Sys.getenv with 190 | | "" -> default |> parse 191 | | exception Not_found -> default |> parse 192 | | _ as x -> x |> parse 193 | 194 | let only: string list list option = 195 | match Env.only |> Sys.getenv with 196 | | "" -> None 197 | | exception Not_found -> None 198 | | _ as x -> 199 | Some ( 200 | x 201 | |> String.split_on_char ',' 202 | |> List.map (String.split_on_char '.') 203 | ) 204 | 205 | let rec should_log path only = 206 | match (path, only) with 207 | | (_, []) -> true 208 | | ([], _::_) -> false 209 | | (p::path, o::only) -> 210 | if o <> p 211 | then false 212 | else should_log path only 213 | 214 | let should_log ~only path = 215 | let path = 216 | path 217 | |> Code_path.fully_qualified_path 218 | |> String.split_on_char '.' in 219 | let finder = path |> should_log in 220 | match only |> List.find_opt finder with 221 | | Some _ -> true 222 | | None -> false 223 | 224 | module Ast = struct 225 | let rec list ?expr xs = 226 | match (expr, xs) with 227 | | (None, []) -> 228 | Exp.construct 229 | {txt = Lident "[]"; loc = !default_loc} 230 | None 231 | | (Some expr, []) -> 232 | Exp.construct 233 | {txt = Lident "::"; loc = !default_loc} 234 | (Some expr) 235 | | (None, x::xs) -> 236 | xs |> ( 237 | list 238 | ~expr: 239 | (Exp.tuple [ 240 | Exp.constant (Const.string x); 241 | Exp.construct 242 | {txt = Lident "[]"; loc = !default_loc} 243 | None 244 | ]) 245 | ) 246 | | (Some expr, x::xs) -> 247 | xs |> ( 248 | list 249 | ~expr: 250 | (Exp.tuple [ 251 | Exp.constant (Const.string x); 252 | Exp.construct 253 | {txt = Lident "::"; loc = !default_loc} 254 | (Some expr) 255 | ]) 256 | ) 257 | 258 | let module_arg cp = 259 | Exp.record 260 | [ 261 | ( 262 | {txt = Lident "rootModule"; loc = !default_loc}, 263 | Exp.constant (Const.string (cp |> Code_path.main_module_name)) 264 | ); 265 | ( 266 | {txt = Lident "subModulePath"; loc = !default_loc}, 267 | cp |> Code_path.submodule_path |> List.rev |> list 268 | ); 269 | ( 270 | {txt = Lident "value"; loc = !default_loc}, 271 | match cp |> Code_path.value with 272 | | Some value -> 273 | Exp.construct 274 | {txt = Lident "Some"; loc = !default_loc} 275 | (Some (Exp.constant (Const.string value))) 276 | | None -> 277 | Exp.construct 278 | {txt = Lident "None"; loc = !default_loc} 279 | None 280 | ); 281 | ( 282 | {txt = Lident "fullPath"; loc = !default_loc}, 283 | Exp.constant (Const.string (cp |> Code_path.fully_qualified_path)) 284 | ); 285 | ] 286 | None 287 | 288 | let logger fn = 289 | Exp.ident {txt = Ldot (logger, fn |> Fn.to_string); loc = !default_loc} 290 | 291 | let log fn cp x = 292 | Exp.apply 293 | (fn |> logger) 294 | [ 295 | (Nolabel, cp |> module_arg); 296 | (Nolabel, x); 297 | ] 298 | 299 | let log1 fn cp x1 x = 300 | Exp.apply 301 | (fn |> logger) 302 | [ 303 | (Nolabel, cp |> module_arg); 304 | (Nolabel, x); 305 | (Nolabel, x1); 306 | ] 307 | 308 | let log2 fn cp x1 x2 x = 309 | Exp.apply 310 | (fn |> logger) 311 | [ 312 | (Nolabel, cp |> module_arg); 313 | (Nolabel, x); 314 | (Nolabel, x1); 315 | (Nolabel, x2); 316 | ] 317 | 318 | let log3 fn cp x1 x2 x3 x = 319 | Exp.apply 320 | (fn |> logger) 321 | [ 322 | (Nolabel, cp |> module_arg); 323 | (Nolabel, x); 324 | (Nolabel, x1); 325 | (Nolabel, x2); 326 | (Nolabel, x3); 327 | ] 328 | 329 | let log4 fn cp x1 x2 x3 x4 x = 330 | Exp.apply 331 | (fn |> logger) 332 | [ 333 | (Nolabel, cp |> module_arg); 334 | (Nolabel, x); 335 | (Nolabel, x1); 336 | (Nolabel, x2); 337 | (Nolabel, x3); 338 | (Nolabel, x4); 339 | ] 340 | 341 | let log5 fn cp x1 x2 x3 x4 x5 x = 342 | Exp.apply 343 | (fn |> logger) 344 | [ 345 | (Nolabel, cp |> module_arg); 346 | (Nolabel, x); 347 | (Nolabel, x1); 348 | (Nolabel, x2); 349 | (Nolabel, x3); 350 | (Nolabel, x4); 351 | (Nolabel, x5); 352 | ] 353 | 354 | let log6 fn cp x1 x2 x3 x4 x5 x6 x = 355 | Exp.apply 356 | (fn |> logger) 357 | [ 358 | (Nolabel, cp |> module_arg); 359 | (Nolabel, x); 360 | (Nolabel, x1); 361 | (Nolabel, x2); 362 | (Nolabel, x3); 363 | (Nolabel, x4); 364 | (Nolabel, x5); 365 | (Nolabel, x6); 366 | ] 367 | 368 | let log7 fn cp x1 x2 x3 x4 x5 x6 x7 x = 369 | Exp.apply 370 | (fn |> logger) 371 | [ 372 | (Nolabel, cp |> module_arg); 373 | (Nolabel, x); 374 | (Nolabel, x1); 375 | (Nolabel, x2); 376 | (Nolabel, x3); 377 | (Nolabel, x4); 378 | (Nolabel, x5); 379 | (Nolabel, x6); 380 | (Nolabel, x7); 381 | ] 382 | 383 | let nothing = 384 | Exp.construct 385 | {txt = Lident "()"; loc = !default_loc} 386 | None 387 | end 388 | 389 | module LogExt = struct 390 | open Ast 391 | 392 | let transform 393 | ~ext_level: (ext_level: Level.t) 394 | ~env_level: (env_level: Level.t option) 395 | ~context: (context: Expansion_context.Extension.t) 396 | (payload: payload) 397 | = 398 | let cp = context |> Expansion_context.Extension.code_path in 399 | match only with 400 | | Some only when not (cp |> should_log ~only) -> nothing 401 | | Some _ 402 | | None -> 403 | match payload with 404 | | PStr({pstr_desc = Pstr_eval (x, _)}::[]) -> 405 | ( 406 | match (ext_level, env_level) with 407 | | (Trace, Some (Trace)) -> x |> log Trace cp 408 | | (Debug, Some (Trace | Debug)) -> x |> log Debug cp 409 | | (Info, Some (Trace | Debug | Info)) -> x |> log Info cp 410 | | (Warn, Some (Trace | Debug | Info | Warn)) -> x |> log Warn cp 411 | | (Error, Some (Trace | Debug | Info | Warn | Error)) -> x |> log Error cp 412 | | ((Trace | Debug | Info | Warn | Error), _) -> nothing 413 | ) 414 | 415 | | PStr( 416 | {pstr_desc = Pstr_eval (x, _)}:: 417 | {pstr_desc = Pstr_eval (x1, _)}::[]) -> 418 | ( 419 | match (ext_level, env_level) with 420 | | (Trace, Some (Trace)) -> x |> log1 Trace1 cp x1 421 | | (Debug, Some (Trace | Debug)) -> x |> log1 Debug1 cp x1 422 | | (Info, Some (Trace | Debug | Info)) -> x |> log1 Info1 cp x1 423 | | (Warn, Some (Trace | Debug | Info | Warn)) -> x |> log1 Warn1 cp x1 424 | | (Error, Some (Trace | Debug | Info | Warn | Error)) -> x |> log1 Error1 cp x1 425 | | ((Trace | Debug | Info | Warn | Error), _) -> nothing 426 | ) 427 | 428 | | PStr( 429 | {pstr_desc = Pstr_eval (x, _)}:: 430 | {pstr_desc = Pstr_eval (x1, _)}:: 431 | {pstr_desc = Pstr_eval (x2, _)}::[]) -> 432 | ( 433 | match (ext_level, env_level) with 434 | | (Trace, Some (Trace)) -> x |> log2 Trace2 cp x1 x2 435 | | (Debug, Some (Trace | Debug)) -> x |> log2 Debug2 cp x1 x2 436 | | (Info, Some (Trace | Debug | Info)) -> x |> log2 Info2 cp x1 x2 437 | | (Warn, Some (Trace | Debug | Info | Warn)) -> x |> log2 Warn2 cp x1 x2 438 | | (Error, Some (Trace | Debug | Info | Warn | Error)) -> x |> log2 Error2 cp x1 x2 439 | | ((Trace | Debug | Info | Warn | Error), _) -> nothing 440 | ) 441 | 442 | | PStr( 443 | {pstr_desc = Pstr_eval (x, _)}:: 444 | {pstr_desc = Pstr_eval (x1, _)}:: 445 | {pstr_desc = Pstr_eval (x2, _)}:: 446 | {pstr_desc = Pstr_eval (x3, _)}::[]) -> 447 | ( 448 | match (ext_level, env_level) with 449 | | (Trace, Some (Trace)) -> x |> log3 Trace3 cp x1 x2 x3 450 | | (Debug, Some (Trace | Debug)) -> x |> log3 Debug3 cp x1 x2 x3 451 | | (Info, Some (Trace | Debug | Info)) -> x |> log3 Info3 cp x1 x2 x3 452 | | (Warn, Some (Trace | Debug | Info | Warn)) -> x |> log3 Warn3 cp x1 x2 x3 453 | | (Error, Some (Trace | Debug | Info | Warn | Error)) -> x |> log3 Error3 cp x1 x2 x3 454 | | ((Trace | Debug | Info | Warn | Error), _) -> nothing 455 | ) 456 | 457 | | PStr( 458 | {pstr_desc = Pstr_eval (x, _)}:: 459 | {pstr_desc = Pstr_eval (x1, _)}:: 460 | {pstr_desc = Pstr_eval (x2, _)}:: 461 | {pstr_desc = Pstr_eval (x3, _)}:: 462 | {pstr_desc = Pstr_eval (x4, _)}::[]) -> 463 | ( 464 | match (ext_level, env_level) with 465 | | (Trace, Some (Trace)) -> x |> log4 Trace4 cp x1 x2 x3 x4 466 | | (Debug, Some (Trace | Debug)) -> x |> log4 Debug4 cp x1 x2 x3 x4 467 | | (Info, Some (Trace | Debug | Info)) -> x |> log4 Info4 cp x1 x2 x3 x4 468 | | (Warn, Some (Trace | Debug | Info | Warn)) -> x |> log4 Warn4 cp x1 x2 x3 x4 469 | | (Error, Some (Trace | Debug | Info | Warn | Error)) -> x |> log4 Error4 cp x1 x2 x3 x4 470 | | ((Trace | Debug | Info | Warn | Error), _) -> nothing 471 | ) 472 | 473 | | PStr( 474 | {pstr_desc = Pstr_eval (x, _)}:: 475 | {pstr_desc = Pstr_eval (x1, _)}:: 476 | {pstr_desc = Pstr_eval (x2, _)}:: 477 | {pstr_desc = Pstr_eval (x3, _)}:: 478 | {pstr_desc = Pstr_eval (x4, _)}:: 479 | {pstr_desc = Pstr_eval (x5, _)}::[]) -> 480 | ( 481 | match (ext_level, env_level) with 482 | | (Trace, Some (Trace)) -> x |> log5 Trace5 cp x1 x2 x3 x4 x5 483 | | (Debug, Some (Trace | Debug)) -> x |> log5 Debug5 cp x1 x2 x3 x4 x5 484 | | (Info, Some (Trace | Debug | Info)) -> x |> log5 Info5 cp x1 x2 x3 x4 x5 485 | | (Warn, Some (Trace | Debug | Info | Warn)) -> x |> log5 Warn5 cp x1 x2 x3 x4 x5 486 | | (Error, Some (Trace | Debug | Info | Warn | Error)) -> x |> log5 Error5 cp x1 x2 x3 x4 x5 487 | | ((Trace | Debug | Info | Warn | Error), _) -> nothing 488 | ) 489 | 490 | | PStr( 491 | {pstr_desc = Pstr_eval (x, _)}:: 492 | {pstr_desc = Pstr_eval (x1, _)}:: 493 | {pstr_desc = Pstr_eval (x2, _)}:: 494 | {pstr_desc = Pstr_eval (x3, _)}:: 495 | {pstr_desc = Pstr_eval (x4, _)}:: 496 | {pstr_desc = Pstr_eval (x5, _)}:: 497 | {pstr_desc = Pstr_eval (x6, _)}::[]) -> 498 | ( 499 | match (ext_level, env_level) with 500 | | (Trace, Some (Trace)) -> x |> log6 Trace6 cp x1 x2 x3 x4 x5 x6 501 | | (Debug, Some (Trace | Debug)) -> x |> log6 Debug6 cp x1 x2 x3 x4 x5 x6 502 | | (Info, Some (Trace | Debug | Info)) -> x |> log6 Info6 cp x1 x2 x3 x4 x5 x6 503 | | (Warn, Some (Trace | Debug | Info | Warn)) -> x |> log6 Warn6 cp x1 x2 x3 x4 x5 x6 504 | | (Error, Some (Trace | Debug | Info | Warn | Error)) -> x |> log6 Error6 cp x1 x2 x3 x4 x5 x6 505 | | ((Trace | Debug | Info | Warn | Error), _) -> nothing 506 | ) 507 | 508 | | PStr( 509 | {pstr_desc = Pstr_eval (x, _)}:: 510 | {pstr_desc = Pstr_eval (x1, _)}:: 511 | {pstr_desc = Pstr_eval (x2, _)}:: 512 | {pstr_desc = Pstr_eval (x3, _)}:: 513 | {pstr_desc = Pstr_eval (x4, _)}:: 514 | {pstr_desc = Pstr_eval (x5, _)}:: 515 | {pstr_desc = Pstr_eval (x6, _)}:: 516 | {pstr_desc = Pstr_eval (x7, _)}::[]) -> 517 | ( 518 | match (ext_level, env_level) with 519 | | (Trace, Some (Trace)) -> x |> log7 Trace7 cp x1 x2 x3 x4 x5 x6 x7 520 | | (Debug, Some (Trace | Debug)) -> x |> log7 Debug7 cp x1 x2 x3 x4 x5 x6 x7 521 | | (Info, Some (Trace | Debug | Info)) -> x |> log7 Info7 cp x1 x2 x3 x4 x5 x6 x7 522 | | (Warn, Some (Trace | Debug | Info | Warn)) -> x |> log7 Warn7 cp x1 x2 x3 x4 x5 x6 x7 523 | | (Error, Some (Trace | Debug | Info | Warn | Error)) -> x |> log7 Error7 cp x1 x2 x3 x4 x5 x6 x7 524 | | ((Trace | Debug | Info | Warn | Error), _) -> nothing 525 | ) 526 | 527 | | _ -> 528 | Location.raise_errorf 529 | ~loc: (context |> Expansion_context.Extension.extension_point_loc) 530 | "Too many arguments" 531 | 532 | let trace = 533 | Context_free.Rule.extension 534 | ( 535 | Extension.V3.declare 536 | "log.trace" 537 | Extension.Context.expression 538 | Ast_pattern.__ 539 | ( 540 | fun ~ctxt -> 541 | transform 542 | ~ext_level: Trace 543 | ~env_level: level 544 | ~context: ctxt 545 | ) 546 | ) 547 | 548 | let debug = 549 | Context_free.Rule.extension 550 | ( 551 | Extension.V3.declare 552 | "log.debug" 553 | Extension.Context.expression 554 | Ast_pattern.__ 555 | ( 556 | fun ~ctxt -> 557 | transform 558 | ~ext_level: Debug 559 | ~env_level: level 560 | ~context: ctxt 561 | ) 562 | ) 563 | 564 | let info = 565 | Context_free.Rule.extension 566 | ( 567 | Extension.V3.declare 568 | "log.info" 569 | Extension.Context.expression 570 | Ast_pattern.__ 571 | ( 572 | fun ~ctxt -> 573 | transform 574 | ~ext_level: Info 575 | ~env_level: level 576 | ~context: ctxt 577 | ) 578 | ) 579 | 580 | let warn = 581 | Context_free.Rule.extension 582 | ( 583 | Extension.V3.declare 584 | "log.warn" 585 | Extension.Context.expression 586 | Ast_pattern.__ 587 | ( 588 | fun ~ctxt -> 589 | transform 590 | ~ext_level: Warn 591 | ~env_level: level 592 | ~context: ctxt 593 | ) 594 | ) 595 | 596 | let error = 597 | Context_free.Rule.extension 598 | ( 599 | Extension.V3.declare 600 | "log.error" 601 | Extension.Context.expression 602 | Ast_pattern.__ 603 | ( 604 | fun ~ctxt -> 605 | transform 606 | ~ext_level: Error 607 | ~env_level: level 608 | ~context: ctxt 609 | ) 610 | ) 611 | end 612 | 613 | module LogAttr = struct 614 | open Ast 615 | 616 | let attr = 617 | Attribute.declare 618 | "log" 619 | Attribute.Context.expression 620 | ( 621 | T 622 | ( 623 | fun ctx loc x k -> 624 | match x with 625 | | PStr [] -> 626 | ctx.matched <- ctx.matched + 1; 627 | None |> k 628 | | PStr( 629 | { 630 | pstr_desc = 631 | Pstr_eval( 632 | {pexp_desc = Pexp_constant (Pconst_string (x, _loc, _))}, 633 | _ 634 | ) 635 | }::[]) -> 636 | ctx.matched <- ctx.matched + 1; 637 | Some x |> k 638 | | _ -> Location.raise_errorf ~loc "Expected string" 639 | ) 640 | ) 641 | (fun x -> x) 642 | 643 | let format ns ctx tag = 644 | match ns with 645 | | None -> 646 | ( 647 | match ctx with 648 | | `WithoutPayload -> Exp.constant (Pconst_string (tag, !default_loc, None)) 649 | | `WithPayload -> Exp.constant (Pconst_string (tag ^ " with payload", !default_loc, None)) 650 | | `WithNotLoggedPayload -> Exp.constant (Pconst_string (tag ^ " with payload (not logged)", !default_loc, None)) 651 | ) 652 | | Some ns -> 653 | let __ = "::" in 654 | match ctx with 655 | | `WithoutPayload -> Exp.constant (Pconst_string (ns ^ __ ^ tag, !default_loc, None)) 656 | | `WithPayload -> Exp.constant (Pconst_string (ns ^ __ ^ tag ^ " with payload", !default_loc, None)) 657 | | `WithNotLoggedPayload -> Exp.constant (Pconst_string (ns ^ __ ^ tag ^ " with payload (not logged)", !default_loc, None)) 658 | 659 | let payload x = 660 | Exp.tuple 661 | [ 662 | Exp.constant (Pconst_string (x, !default_loc, None)); 663 | Exp.ident {txt = Lident x; loc = !default_loc}; 664 | ] 665 | 666 | let transform 667 | ~env_level: (env_level: Level.t option) 668 | ~namespace: (namespace: string option) 669 | ~context: (context: Expansion_context.Base.t) 670 | (expr: expression) 671 | = 672 | (* TODO: Use Base getters once ppxlib is updated *) 673 | let context = 674 | Expansion_context.Extension.make 675 | ~extension_point_loc: expr.pexp_loc 676 | ~base: context 677 | () in 678 | let cp = context |> Expansion_context.Extension.code_path in 679 | 680 | match only with 681 | | Some only when not (cp |> should_log ~only) -> expr 682 | | Some _ 683 | | None -> 684 | match (expr, env_level) with 685 | | 686 | ( 687 | {pexp_desc = Pexp_match (_, _)} as expr, 688 | (Some (Info | Warn | Error) | None) 689 | ) -> expr 690 | | 691 | ( 692 | {pexp_desc = Pexp_match (match_, cases); pexp_loc; pexp_attributes}, 693 | Some(Trace | Debug) 694 | ) -> 695 | Exp.match_ 696 | ~loc: pexp_loc 697 | ~attrs: pexp_attributes 698 | match_ 699 | ( 700 | cases 701 | |> List.map 702 | ( 703 | function 704 | | 705 | { 706 | pc_lhs = {ppat_desc = Ppat_construct ({txt = Lident tag}, None)} as pattern; 707 | pc_rhs = branch; 708 | } -> 709 | Exp.case 710 | pattern 711 | ( 712 | Exp.sequence 713 | (tag |> format namespace `WithoutPayload |> log Debug cp) 714 | branch 715 | ) 716 | | 717 | { 718 | pc_lhs = 719 | { 720 | ppat_desc = 721 | Ppat_construct ( 722 | {txt = Lident tag}, 723 | Some( 724 | _, 725 | { 726 | ppat_desc = 727 | ( 728 | (Ppat_tuple ({ppat_desc = Ppat_var {txt = x1}}::[]))(* Reason *) 729 | | (Ppat_var {txt = x1}) (* ReScript *) 730 | ) 731 | } 732 | ) 733 | ) 734 | } as pattern; 735 | pc_rhs = branch; 736 | } -> 737 | Exp.case 738 | pattern 739 | ( 740 | Exp.sequence 741 | ( 742 | tag 743 | |> format namespace `WithPayload 744 | |> log1 Debug1 cp (x1 |> payload) 745 | ) 746 | branch 747 | ) 748 | | 749 | { 750 | pc_lhs = 751 | { 752 | ppat_desc = 753 | Ppat_construct ( 754 | {txt = Lident tag}, 755 | Some( 756 | _, 757 | { 758 | ppat_desc = 759 | Ppat_tuple ( 760 | {ppat_desc = Ppat_var {txt = x1}}:: 761 | {ppat_desc = Ppat_var {txt = x2}}::[] 762 | ) 763 | } 764 | ) 765 | ) 766 | } as pattern; 767 | pc_rhs = branch; 768 | } -> 769 | Exp.case 770 | pattern 771 | ( 772 | Exp.sequence 773 | ( 774 | tag 775 | |> format namespace `WithPayload 776 | |> log2 Debug2 cp (x1 |> payload) (x2 |> payload) 777 | ) 778 | branch 779 | ) 780 | | 781 | { 782 | pc_lhs = 783 | { 784 | ppat_desc = 785 | Ppat_construct ( 786 | {txt = Lident tag}, 787 | Some( 788 | _, 789 | { 790 | ppat_desc = 791 | Ppat_tuple ( 792 | {ppat_desc = Ppat_var {txt = x1}}:: 793 | {ppat_desc = Ppat_var {txt = x2}}:: 794 | {ppat_desc = Ppat_var {txt = x3}}::[] 795 | ) 796 | } 797 | ) 798 | ) 799 | } as pattern; 800 | pc_rhs = branch; 801 | } -> 802 | Exp.case 803 | pattern 804 | ( 805 | Exp.sequence 806 | ( 807 | tag 808 | |> format namespace `WithPayload 809 | |> 810 | log3 811 | Debug3 812 | cp 813 | (x1 |> payload) 814 | (x2 |> payload) 815 | (x3 |> payload) 816 | ) 817 | branch 818 | ) 819 | | 820 | { 821 | pc_lhs = 822 | { 823 | ppat_desc = 824 | Ppat_construct ( 825 | {txt = Lident tag}, 826 | Some( 827 | _, 828 | { 829 | ppat_desc = 830 | Ppat_tuple ( 831 | {ppat_desc = Ppat_var {txt = x1}}:: 832 | {ppat_desc = Ppat_var {txt = x2}}:: 833 | {ppat_desc = Ppat_var {txt = x3}}:: 834 | {ppat_desc = Ppat_var {txt = x4}}::[] 835 | ) 836 | } 837 | ) 838 | ) 839 | } as pattern; 840 | pc_rhs = branch; 841 | } -> 842 | Exp.case 843 | pattern 844 | ( 845 | Exp.sequence 846 | ( 847 | tag 848 | |> format namespace `WithPayload 849 | |> 850 | log4 851 | Debug4 852 | cp 853 | (x1 |> payload) 854 | (x2 |> payload) 855 | (x3 |> payload) 856 | (x4 |> payload) 857 | ) 858 | branch 859 | ) 860 | | 861 | { 862 | pc_lhs = 863 | { 864 | ppat_desc = 865 | Ppat_construct ( 866 | {txt = Lident tag}, 867 | Some( 868 | _, 869 | { 870 | ppat_desc = 871 | Ppat_tuple ( 872 | {ppat_desc = Ppat_var {txt = x1}}:: 873 | {ppat_desc = Ppat_var {txt = x2}}:: 874 | {ppat_desc = Ppat_var {txt = x3}}:: 875 | {ppat_desc = Ppat_var {txt = x4}}:: 876 | {ppat_desc = Ppat_var {txt = x5}}::[] 877 | ) 878 | } 879 | ) 880 | ) 881 | } as pattern; 882 | pc_rhs = branch; 883 | } -> 884 | Exp.case 885 | pattern 886 | ( 887 | Exp.sequence 888 | ( 889 | tag 890 | |> format namespace `WithPayload 891 | |> 892 | log5 893 | Debug5 894 | cp 895 | (x1 |> payload) 896 | (x2 |> payload) 897 | (x3 |> payload) 898 | (x4 |> payload) 899 | (x5 |> payload) 900 | ) 901 | branch 902 | ) 903 | | 904 | { 905 | pc_lhs = 906 | { 907 | ppat_desc = 908 | Ppat_construct ( 909 | {txt = Lident tag}, 910 | Some( 911 | _, 912 | { 913 | ppat_desc = 914 | Ppat_tuple ( 915 | {ppat_desc = Ppat_var {txt = x1}}:: 916 | {ppat_desc = Ppat_var {txt = x2}}:: 917 | {ppat_desc = Ppat_var {txt = x3}}:: 918 | {ppat_desc = Ppat_var {txt = x4}}:: 919 | {ppat_desc = Ppat_var {txt = x5}}:: 920 | {ppat_desc = Ppat_var {txt = x6}}::[] 921 | ) 922 | } 923 | ) 924 | ) 925 | } as pattern; 926 | pc_rhs = branch; 927 | } -> 928 | Exp.case 929 | pattern 930 | ( 931 | Exp.sequence 932 | ( 933 | tag 934 | |> format namespace `WithPayload 935 | |> 936 | log6 937 | Debug6 938 | cp 939 | (x1 |> payload) 940 | (x2 |> payload) 941 | (x3 |> payload) 942 | (x4 |> payload) 943 | (x5 |> payload) 944 | (x6 |> payload) 945 | ) 946 | branch 947 | ) 948 | | 949 | { 950 | pc_lhs = 951 | { 952 | ppat_desc = 953 | Ppat_construct ( 954 | {txt = Lident tag}, 955 | Some( 956 | _, 957 | { 958 | ppat_desc = 959 | Ppat_tuple ( 960 | {ppat_desc = Ppat_var {txt = x1}}:: 961 | {ppat_desc = Ppat_var {txt = x2}}:: 962 | {ppat_desc = Ppat_var {txt = x3}}:: 963 | {ppat_desc = Ppat_var {txt = x4}}:: 964 | {ppat_desc = Ppat_var {txt = x5}}:: 965 | {ppat_desc = Ppat_var {txt = x6}}:: 966 | {ppat_desc = Ppat_var {txt = x7}}::[] 967 | ) 968 | } 969 | ) 970 | ) 971 | } as pattern; 972 | pc_rhs = branch; 973 | } -> 974 | Exp.case 975 | pattern 976 | ( 977 | Exp.sequence 978 | ( 979 | tag 980 | |> format namespace `WithPayload 981 | |> 982 | log7 983 | Debug7 984 | cp 985 | (x1 |> payload) 986 | (x2 |> payload) 987 | (x3 |> payload) 988 | (x4 |> payload) 989 | (x5 |> payload) 990 | (x6 |> payload) 991 | (x7 |> payload) 992 | ) 993 | branch 994 | ) 995 | | 996 | { 997 | pc_lhs = {ppat_desc = Ppat_construct({txt = Lident tag}, Some _)} as pattern; 998 | pc_rhs = branch; 999 | } -> 1000 | Exp.case 1001 | pattern 1002 | ( 1003 | Exp.sequence 1004 | ( 1005 | tag 1006 | |> format namespace `WithNotLoggedPayload 1007 | |> log Debug cp 1008 | ) 1009 | branch 1010 | ) 1011 | | {pc_lhs = pattern; pc_rhs = branch} -> Exp.case pattern branch 1012 | ) 1013 | ) 1014 | 1015 | | ({pexp_loc}, _) -> Location.raise_errorf ~loc: pexp_loc "Expected pattern matching" 1016 | 1017 | let impl = 1018 | ( 1019 | object (_self) 1020 | inherit Ast_traverse.map_with_expansion_context_and_errors as super 1021 | 1022 | method! expression ctx expr = 1023 | let expr, errors = super#expression ctx expr in 1024 | match expr |> Attribute.get attr with 1025 | | None -> (expr, errors) 1026 | | Some namespace -> 1027 | let expr = expr |> transform ~env_level:level ~namespace ~context:ctx in 1028 | (expr, errors) 1029 | 1030 | method! structure ctx str = 1031 | let str, errors = super#structure ctx str in 1032 | Attribute.check_all_seen (); 1033 | (str, errors) 1034 | end 1035 | )#structure 1036 | end 1037 | 1038 | module File_path = struct 1039 | let chop_prefix ~prefix x = 1040 | let prefix_len = String.length prefix in 1041 | let x_len = String.length x in 1042 | if x_len >= prefix_len && String.sub x 0 prefix_len = prefix then 1043 | Some (String.sub x prefix_len (x_len - prefix_len)) 1044 | else 1045 | None 1046 | 1047 | let get_default_path (loc : Location.t) = 1048 | let fname = loc.loc_start.pos_fname in 1049 | match chop_prefix ~prefix:"./" fname with 1050 | | Some fname -> fname 1051 | | None -> fname 1052 | 1053 | let get_default_path_str : structure -> string = function 1054 | | [] -> "" 1055 | | { pstr_loc = loc; _ } :: _ -> get_default_path loc 1056 | 1057 | let get_default_path_sig : signature -> string = function 1058 | | [] -> "" 1059 | | { psig_loc = loc; _ } :: _ -> get_default_path loc 1060 | end 1061 | 1062 | let _ = 1063 | "rescript-logger-ppx" 1064 | |> 1065 | Driver.register_transformation 1066 | ~rules: (let open LogExt in [trace; debug; info; warn; error]) 1067 | ~impl: ( 1068 | fun str -> 1069 | let path = str |> File_path.get_default_path_str in 1070 | let ctx = 1071 | Expansion_context.Base.top_level 1072 | ~tool_name: (Ocaml_common.Ast_mapper.tool_name ()) 1073 | ~file_path: path 1074 | ~input_name: ( 1075 | (* I'm not sure if it's what meant by `input_name` *) 1076 | match path |> Filename.basename |> Filename.chop_extension with 1077 | | x -> x 1078 | | exception _ -> "" 1079 | ) 1080 | in 1081 | let str, _ = str |> LogAttr.impl ctx in 1082 | str 1083 | ) 1084 | 1085 | let _ = Driver.add_arg LibArg.key LibArg.spec ~doc:LibArg.doc 1086 | -------------------------------------------------------------------------------- /ppx/lib/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name lib) 3 | (public_name rescript-logger-ppx.lib) 4 | (kind ppx_rewriter) 5 | (libraries ppxlib) 6 | (flags (:standard -w -30-9)) 7 | (preprocess (pps ppxlib.metaquot))) 8 | -------------------------------------------------------------------------------- /rescript-logger-ppx.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | name: "rescript-logger-ppx" 3 | version: "4.0.0" 4 | synopsis: "Logging implementation for ReScript" 5 | description: """ 6 | Logging implementation for ReScript 7 | """ 8 | maintainer: "Alex Fedoseev " 9 | authors: "Alex Fedoseev " 10 | license: "MIT" 11 | homepage: "https://github.com/shakacode/rescript-logger.git" 12 | bug-reports: "https://github.com/shakacode/rescript-logger/issues" 13 | dev-repo: "git+https://github.com/shakacode/rescript-logger.git" 14 | depends: [ 15 | "ocaml" { = "4.14.1" } 16 | "dune" { = "3.11.1" } 17 | "ppxlib" { = "0.30.0" } 18 | ] 19 | build: [ 20 | ["dune" "build" "-p" name "-j" jobs] 21 | ] 22 | -------------------------------------------------------------------------------- /windows.patch: -------------------------------------------------------------------------------- 1 | diff --git a/rescript-logger-ppx.opam b/rescript-logger-ppx.opam 2 | index f270f4d..1cd834e 100644 3 | --- a/rescript-logger-ppx.opam 4 | +++ b/rescript-logger-ppx.opam 5 | @@ -13,8 +13,8 @@ bug-reports: "https://github.com/shakacode/rescript-logger/issues" 6 | dev-repo: "git+https://github.com/shakacode/rescript-logger.git" 7 | depends: [ 8 | "ocaml" { = "4.14.1" } 9 | - "dune" { = "3.11.1" } 10 | - "ppxlib" { = "0.30.0" } 11 | + "dune" { = "3.5.0" } 12 | + "ppxlib" { = "0.28.0" } 13 | ] 14 | build: [ 15 | ["dune" "build" "-p" name "-j" jobs] 16 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | rescript@11.0.1: 6 | version "11.0.1" 7 | resolved "https://registry.yarnpkg.com/rescript/-/rescript-11.0.1.tgz#c74af134dc8a16d152169b2456d0720324835f54" 8 | integrity sha512-7T4PRp/d0+CBNnY6PYKffFqo9tGZlvnZpboF/n+8SKS+JZ6VvXJO7W538VPZXf3EYx1COGAWWvkF9e/HgSAqHg== 9 | --------------------------------------------------------------------------------