Skip to content

Commit ec22e8f

Browse files
committed
allow setting logging level via NANONEXT_LOG
1 parent 967bfc6 commit ec22e8f

19 files changed

+128
-72
lines changed

NEWS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
#### New Features
44

5-
* Aio fields `$result` for a 'sendAio', `$raw` and `$data` for a 'recvAio' may be queried directly, returning their values or else an NA 'unresolved value' if the Aio operation is yet to complete.
6-
* `unresolved()` added as an auxiliary function to query whether an Aio is still unresolved in a non-blocking fashion.
5+
* Aio values `$result`, `$raw` or `$data` now resolve without requiring `call_aio()`. Access the values directly and an NA 'unresolved value' will be returned if the Aio operation is yet to complete.
6+
* `unresolved()` added as an auxiliary function to query whether an Aio is unresolved, for use in control flow statements.
77
* `is_nul_byte()` added as a helper function for request/reply setups.
88
* `survey_time()` added as a convenience function for surveyor/respondent patterns.
9-
* `logging()` function to specify a global package logging level - currently supports 'error' and 'info'.
9+
* `logging()` function to specify a global package logging level - 'error' or 'info'. Automatically polls the environment variable 'NANONEXT_LOG' on package load and then each time `logging(level = "check")` is called, allowing this to be set externally.
1010
* `ncurl()` adds a '...' argument. Support for HTTP methods other than GET.
1111

1212
#### Updates

R/aio.R

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,16 @@
2626
#' Once the result has been successfully retrieved, the Aio is deallocated
2727
#' and only the result is stored in the Aio object.
2828
#'
29-
#' @section Non-blocking:
29+
#' @section Alternatively:
3030
#'
31-
#' To query the value of an Aio without potentially waiting for the Aio
32-
#' operation to complete, access the values directly at \code{$result} for a
33-
#' 'sendAio', and \code{$raw} or \code{$data} for a 'recvAio'.
31+
#' Aio values may be accessed directly at \code{$result} for a 'sendAio',
32+
#' and \code{$raw} or \code{$data} for a 'recvAio'. If the Aio operation is
33+
#' yet to complete, a logical NA 'unresolved value' will be returned. Once
34+
#' completed, the resolved value will be returned instead.
3435
#'
35-
#' If the Aio operation is yet to complete, the result will be an
36-
#' 'unresolved value', which is a logical NA. Once complete, the resolved
37-
#' value will be returned instead.
36+
#' \code{\link{unresolved}} may also be used, which returns TRUE only if an
37+
#' Aio or Aio value has yet to resolve and FALSE otherwise. This is suitable
38+
#' for use in control flow statements such as \code{while} or \code{if}.
3839
#'
3940
#' @examples
4041
#' s1 <- socket("pair", listen = "inproc://nanonext")
@@ -133,16 +134,16 @@ stop_aio <- function(aio) {
133134

134135
#' Query if an Aio is Unresolved
135136
#'
136-
#' Query whether an Aio or Aio value is unresolved. This function is non-blocking
137-
#' unlike \code{\link{call_aio}} which waits for completion.
137+
#' Query whether an Aio or Aio value remains unresolved. Unlike
138+
#' \code{\link{call_aio}}, this function does not wait for completion.
138139
#'
139140
#' @param aio An Aio (object of class 'sendAio' or 'recvAio'), or Aio value
140141
#' stored in \code{$result}, \code{$raw} or \code{$data} as the case may be.
141142
#'
142143
#' @return Logical TRUE or FALSE.
143144
#'
144-
#' @details Returns TRUE for unresolved nanonext Aios or Aio values; returns
145-
#' FALSE in all other cases and for all other objects.
145+
#' @details Returns TRUE for unresolved Aios or Aio values, FALSE otherwise.
146+
#' Suitable for use in control flow statements such as \code{while} or \code{if}.
146147
#'
147148
#' Note: querying resolution may cause a previously unresolved Aio to resolve.
148149
#'

R/context.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ reply <- function(context,
261261
#'
262262
#' @inheritParams reply
263263
#' @inheritParams recv
264-
#' @param data an R object (if send_mode = 'raw', an R vector).
264+
#' @param data an object (if send_mode = 'raw', a vector).
265265
#' @param timeout in ms. If unspecified, a socket-specific default timeout will
266266
#' be used. Note that this applies to receiving the result.
267267
#'

R/methods.R

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,7 @@ close.nanoSocket <- function(con, ...) {
107107
close.nanoContext <- function(con, ...) {
108108

109109
xc <- .Call(rnng_ctx_close, con)
110-
if (xc) {
111-
message(Sys.time(), " [ ", xc, " ] ", nng_error(xc))
112-
} else if (logging()) {
113-
cat(format.POSIXct(Sys.time()), "[ ctxt close ] id:",
114-
attr(con, "id"), "| sock:", attr(con, "socket"), "\n", file = stdout())
115-
}
110+
if (xc) message(Sys.time(), " [ ", xc, " ] ", nng_error(xc))
116111
invisible(xc)
117112

118113
}

R/sendrecv.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#' Send data over a Socket.
66
#'
77
#' @param socket a Socket.
8-
#' @param data an R object (if mode = 'raw', an R vector).
8+
#' @param data an object (if mode = 'raw', a vector).
99
#' @param mode [default 'serial'] whether data will be sent serialized or as a
1010
#' raw vector. Use 'serial' for sending and receiving within R to ensure
1111
#' perfect reproducibility. Use 'raw' for sending vectors of any type (will be

R/socket.R

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,15 @@ socket <- function(protocol = c("pair", "bus", "push", "pull", "req", "rep",
104104
#' @examples
105105
#' pub <- socket("pub", listen = "inproc://nanonext")
106106
#' sub <- socket("sub", dial = "inproc://nanonext")
107+
#' logging(level = "info")
107108
#'
108109
#' subscribe(sub, "examples")
109110
#' send(pub, c("examples", "this is an example"), mode = "raw")
110111
#' recv(sub, "character")
111112
#' send(pub, c("other", "this other topic will not be received"), mode = "raw")
112113
#' recv(sub, "character")
113114
#'
115+
#' logging(level = "error")
114116
#' close(pub)
115117
#' close(sub)
116118
#'
@@ -156,6 +158,7 @@ subscribe <- function(socket, topic = NULL) {
156158
#' @examples
157159
#' pub <- socket("pub", listen = "inproc://nanonext")
158160
#' sub <- socket("sub", dial = "inproc://nanonext")
161+
#' logging(level = "info")
159162
#'
160163
#' subscribe(sub, NULL)
161164
#' send(pub, c("examples", "this is an example"), mode = "raw")
@@ -164,6 +167,7 @@ subscribe <- function(socket, topic = NULL) {
164167
#' send(pub, c("examples", "this example will not be received"), mode = "raw")
165168
#' recv(sub, "character")
166169
#'
170+
#' logging(level = "error")
167171
#' close(pub)
168172
#' close(sub)
169173
#'
@@ -193,10 +197,7 @@ unsubscribe <- function(socket, topic = NULL) {
193197
#'
194198
#' @return Zero (invisibly) on success.
195199
#'
196-
#' @details This is a convenience function that wraps \code{\link{setopt}} with
197-
#' the correct parameters.
198-
#'
199-
#' After using this function, to start a new survey, the surveyor must:
200+
#' @details After using this function, to start a new survey, the surveyor must:
200201
#' \itemize{
201202
#' \item{send a message using any of the send functions.}
202203
#' \item{switch to receiving responses.}
@@ -212,28 +213,33 @@ unsubscribe <- function(socket, topic = NULL) {
212213
#' @examples
213214
#' sur <- socket("surveyor", listen = "inproc://nanonext")
214215
#' res <- socket("respondent", dial = "inproc://nanonext")
216+
#' logging(level = "info")
215217
#'
216218
#' survey_time(sur, 1000)
217219
#' send(sur, "reply to this survey")
218220
#' aio <- recv_aio(sur)
219221
#'
220222
#' recv(res)
221-
#' send_aio(res, "replied")
223+
#' s <- send_aio(res, "replied")
222224
#'
223225
#' call_aio(aio)$data
224226
#'
227+
#' logging(level = "error")
225228
#' close(sur)
226229
#' close(res)
227230
#'
228231
#' @export
229232
#'
230233
survey_time <- function(socket, time) {
231234

232-
res <- setopt(socket, type = "ms", opt = "surveyor:survey-time", value = time)
233-
if (logging()) {
235+
xc <- .Call(rnng_socket_set_ms, socket, "surveyor:survey-time", time)
236+
if (xc) {
237+
message(Sys.time(), " [ ", xc, " ] ", nng_error(xc))
238+
} else if (logging()) {
234239
cat(format.POSIXct(Sys.time()), "[ survey ] sock:", attr(socket, "id"),
235240
"| set time:", time, "\n", file = stdout())
236241
}
242+
invisible(xc)
237243

238244
}
239245

R/utils.R

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,23 @@ is_nul_byte <- function(x) {
8383
#'
8484
#' Set the logging level of nanonext.
8585
#'
86-
#' @param level specify a logging level - either 'error' (default) which sends
87-
#' all NNG errors to stderr or 'info' which also sends informational events
88-
#' such as socket open, listener/dialer start, socket close etc. to stdout.
86+
#' @param level specify a logging level
87+
#' \itemize{
88+
#' \item{'prev'} {which continues with the previous logging level}
89+
#' \item{'check'} {which checks the value of environment variable 'NANONEXT_LOG'}
90+
#' \item{'error'} {which sends all NNG errors to stderr}
91+
#' \item{'info'} {which in addition sends key informational events such as
92+
#' socket open etc. to stdout.}
93+
#' }
8994
#'
9095
#' @return Invisible NULL, or if 'level' is not specified, the integer code of
91-
#' the logging level.
96+
#' the logging level. A confirmation is printed to the console (stdout) if
97+
#' the logging level has changed.
98+
#'
99+
#' @details The environment variable 'NANONEXT_LOG' is checked automatically on
100+
#' package load and then cached for optimal performance. It is also checked
101+
#' each time \code{logging(level = "check")} is called. If the variable is
102+
#' set incorrectly, the default level of 'error' is used instead.
92103
#'
93104
#' @examples
94105
#' logging(level = "info")
@@ -100,17 +111,24 @@ is_nul_byte <- function(x) {
100111
#'
101112
logging <- function(level) {
102113

103-
cache <- 0L
114+
cache <- switch(tolower(Sys.getenv("NANONEXT_LOG")),
115+
info = 1L,
116+
0L)
104117

105-
logging <- function(level = c("error", "info")) {
118+
logging <- function(level = c("prev", "check", "error", "info")) {
106119

107120
missing(level) && return(cache)
108121
level <- match.arg(level)
122+
original <- cache
109123
cache <<- switch(level,
124+
check = switch(tolower(Sys.getenv("NANONEXT_LOG")),
125+
info = 1L,
126+
0L),
110127
error = 0L,
111-
info = 1L)
112-
cat(format.POSIXct(Sys.time()), "[ log level ] set to:", level,
113-
"\n", file = stdout())
128+
info = 1L,
129+
prev = original)
130+
if (cache != original) cat(format.POSIXct(Sys.time()), "[ log level ] set to:",
131+
if (cache) "info\n" else "error\n", file = stdout())
114132

115133
}
116134

README.Rmd

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,12 @@ In such a case, using `call_aio()` confirms that the operation has completed (or
277277

278278
{nanonext} fully implements NNG's pub/sub protocol as per the below example.
279279

280-
This example uses the new R4.1 pipe for clarity of code, although this is of course not required.
280+
The built-in logging levels are also demonstrated here. NNG errors are always output to stderr and operation is otherwise silent by default. To enable key information events to be sent to stdout, use `logging(level = "info")`.
281+
282+
The log level can also be set externally in production environments via an environment variable `NANONEXT_LOG`.
281283

282284
```{r pub}
285+
logging(level = "info")
283286
284287
pub <- socket("pub", listen = "inproc://nanobroadcast")
285288
sub <- socket("sub", dial = "inproc://nanobroadcast")

README.md

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ aio
328328
#> - $raw for raw message
329329
#> - $data for message data
330330
str(aio$data)
331-
#> num [1:100000000] -0.771 -0.379 -0.377 -1.401 -1.579 ...
331+
#> num [1:100000000] 0.837 1.301 2.225 1.43 -1.543 ...
332332
```
333333

334334
In this example the calculation is returned, but other operations may
@@ -345,40 +345,57 @@ the function, which may typically be NULL or an exit code.
345345
{nanonext} fully implements NNG’s pub/sub protocol as per the below
346346
example.
347347

348-
This example uses the new R4.1 pipe for clarity of code, although this
349-
is of course not required.
348+
The built-in logging levels are also demonstrated here. NNG errors are
349+
always output to stderr and operation is otherwise silent by default. To
350+
enable key information events to be sent to stdout, use
351+
`logging(level = "info")`.
352+
353+
The log level can also be set externally in production environments via
354+
an environment variable `NANONEXT_LOG`.
350355

351356
``` r
357+
logging(level = "info")
358+
#> 2022-03-03 10:51:39 [ log level ] set to: info
359+
352360
pub <- socket("pub", listen = "inproc://nanobroadcast")
361+
#> 2022-03-03 10:51:39 [ sock open ] id: 9 | protocol: pub
362+
#> 2022-03-03 10:51:39 [ list start ] sock: 9 | url: inproc://nanobroadcast
353363
sub <- socket("sub", dial = "inproc://nanobroadcast")
364+
#> 2022-03-03 10:51:39 [ sock open ] id: 10 | protocol: sub
365+
#> 2022-03-03 10:51:39 [ dial start ] sock: 10 | url: inproc://nanobroadcast
354366

355367
sub |> subscribe(topic = "examples")
368+
#> 2022-03-03 10:51:39 [ subscribe ] sock: 10 | topic: examples
356369
pub |> send(c("examples", "this is an example"), mode = "raw", echo = FALSE)
357370
sub |> recv(mode = "character", keep.raw = FALSE)
358371
#> [1] "examples" "this is an example"
359372

360373
pub |> send(c("other", "this other topic will not be received"), mode = "raw", echo = FALSE)
361374
sub |> recv(mode = "character", keep.raw = FALSE)
362-
#> 2022-03-02 17:01:22 [ 8 ] Try again
375+
#> 2022-03-03 10:51:39 [ 8 ] Try again
363376

364377
# specify NULL to subscribe to ALL topics
365378
sub |> subscribe(topic = NULL)
379+
#> 2022-03-03 10:51:39 [ subscribe ] sock: 10 | topic: ALL
366380
pub |> send(c("newTopic", "this is a new topic"), mode = "raw", echo = FALSE)
367381
sub |> recv("character", keep.raw = FALSE)
368382
#> [1] "newTopic" "this is a new topic"
369383

370384
sub |> unsubscribe(topic = NULL)
385+
#> 2022-03-03 10:51:39 [ unsubscribe ] sock: 10 | topic: ALL
371386
pub |> send(c("newTopic", "this topic will now not be received"), mode = "raw", echo = FALSE)
372387
sub |> recv("character", keep.raw = FALSE)
373-
#> 2022-03-02 17:01:22 [ 8 ] Try again
388+
#> 2022-03-03 10:51:39 [ 8 ] Try again
374389

375390
# however the topics explicitly subscribed to are still received
376391
pub |> send(c("examples", "this example will still be received"), mode = "raw", echo = FALSE)
377392
sub |> recv(mode = "character", keep.raw = FALSE)
378393
#> [1] "examples" "this example will still be received"
379394

380395
close(pub)
396+
#> 2022-03-03 10:51:39 [ sock close ] id: 9 | protocol: pub
381397
close(sub)
398+
#> 2022-03-03 10:51:39 [ sock close ] id: 10 | protocol: sub
382399
```
383400

384401
[« Back to ToC](#table-of-contents)
@@ -394,11 +411,11 @@ ncurl("http://httpbin.org/headers")
394411
#> [1] 7b 0a 20 20 22 68 65 61 64 65 72 73 22 3a 20 7b 0a 20 20 20 20 22 48 6f 73
395412
#> [26] 74 22 3a 20 22 68 74 74 70 62 69 6e 2e 6f 72 67 22 2c 20 0a 20 20 20 20 22
396413
#> [51] 58 2d 41 6d 7a 6e 2d 54 72 61 63 65 2d 49 64 22 3a 20 22 52 6f 6f 74 3d 31
397-
#> [76] 2d 36 32 31 66 61 32 65 33 2d 37 66 31 34 35 62 63 64 31 65 34 34 36 34 61
398-
#> [101] 66 36 62 61 62 63 63 33 64 22 0a 20 20 7d 0a 7d 0a
414+
#> [76] 2d 36 32 32 30 39 64 62 62 2d 34 61 61 66 66 65 31 37 32 61 64 64 35 39 35
415+
#> [101] 35 37 33 31 62 35 34 30 30 22 0a 20 20 7d 0a 7d 0a
399416
#>
400417
#> $data
401-
#> [1] "{\n \"headers\": {\n \"Host\": \"httpbin.org\", \n \"X-Amzn-Trace-Id\": \"Root=1-621fa2e3-7f145bcd1e4464af6babcc3d\"\n }\n}\n"
418+
#> [1] "{\n \"headers\": {\n \"Host\": \"httpbin.org\", \n \"X-Amzn-Trace-Id\": \"Root=1-62209dbb-4aaffe172add5955731b5400\"\n }\n}\n"
402419
```
403420

404421
For advanced use, supports additional HTTP methods such as POST or PUT.

man/call_aio.Rd

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)