-
Notifications
You must be signed in to change notification settings - Fork 298
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Log2file #293
Log2file #293
Conversation
This should get a better default location for the log, but for that I would need to know where to put logfiles... @takluyver Is there some "default location", where all kernels should log to? the ipykernel still uses the old ipython profile support, so that is not gonna work for us... |
@@ -7,19 +7,53 @@ | |||
stderror <- stderr() | |||
|
|||
log_debug <- function(...) { | |||
if (getOption('jupyter.log_level') >= 3L) { | |||
cat('DEBUG: ', sprintf(...), '\n', sep = '', file = stderror) | |||
if (isTRUE(getOption('jupyter.log_level') >= 3L)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is added isTRUE
to guard against the case where a user removes an option...
i’d prefer to use |
cat('DEBUG: ', sprintf(...), '\n', sep = '', file = stderror) | ||
if (isTRUE(getOption('jupyter.log_level') >= 3L)) { | ||
log_msg_stderror('DEBUG', sprintf(...)) | ||
log_msg_logfile('DEBUG', sprintf(...)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i’d design it like this:
log_debug <- function(...) {
if (isTRUE(getOption('jupyter.log_level') >= 3L)) {
log_msg('DEBUG', sprintf(...))
}
}
log_msg <- function(lvl, msg) {
log_msg_stderror(lvl, msg)
if (isTRUE(getOption('jupyter.log_to_file'))) {
log_msg_logfile(lvl, msg)
}
}
log_msg_stderror <- ...
log_msg_logfile <- ... #without the if()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tried that, but then wanted to send the filename to the normal log and didn't want to get into recursion and so split both calls...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eh, you can still use the individual ones, i just wrapped them into log_msg
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, no I got it.... Update is on the way...
all those design considerations nonwithstanding, i’m actually against enhancing our logging, and for switching to a dedicated logging system.
obviously all of this helps with debugging, but i don’t want us to live in our own NIH-fueled wheel-reinventing bubble. we obviously need a solution that has per-package logging so that we can debug only the kernel without seeing all the crap packages log. @JanSchulz are you OK with closing this and deciding on a dedicated solution in #119 this week? |
I'm not so sure: I agree that we should go to a proper lib, but unless someone does that, it would be nice to have a way to get properly encoded logs from the kernel (the log in the notebook windows is garbled wrt unicode... :-() |
ok, sounds reasonable... |
Whatever we do merge the log_to_file part: the other commit of adding more logging calls in the real code should be merged... |
Ok, I take that back: IMO it should be "enable it and get a logfile wherever jupyter logs to, too". But that's probably better done in a later version... |
i don’t get it. my semantics for a single log file option would optimally be:
but the above behavior is for IRkernel, not our logging system. a proper logging system should allow registering arbitrarily many loggers: to files, to databases, to, stderr, … |
My semantics are based on the one in ipython: if you enable logging in the ipyparallel engines, AFAIK it logs to My preferences would be to log to |
hmm, OK. i think jupyter specific logging options won’t hurt. bonus points if we can configure the future real logging system according to them. about the paths, you should check
so if anything of those, the last one should be used. the first one isn’t available after kernel shutdown, and the second one is the config dir, not “all kinds of stuff dir” |
Enable logging to a file via ``` options(jupyter.log_level = 3) # log debug options(jupyter.log_to_file = TRUE) # log to file options(jupyter.logfile = 'irkernel.log') # default, relative to current dir! ``` The default log is 'irkernel.log' in the current directory. This probably should change, but I haven't yet looked where the other kernels log to...
Checking this is not gonna work: You don't need to have jupyter stuff in path (e.g. only installed in a conda environment)... |
well, then there’s no possible way to deduce the correct jupyter directory. but you know what: the correct system log directory is
the correct user log dir is
if you want we can provide a function: get_log_dir() {
logfile <- getOption('jupyter.logfile')
if (is.null(logfile) || identical(logfile, FALSE)) {
NULL
} else if (is.character(logfile)) {
logfile
} else if (isTRUE(logfile)) {
# logic to get OS specific log dir
} else stop(sprintf('Option %s of unknown type %s instead of logical, character, or NULL', sQuote('jupyter.logfile'), class(logfile)))
} |
@takluyver Do you know of any recommendation for kernels where to place logfiles? |
the above are OS-level recommendations on where everything should put logfiles. |
Sorry for the delay on this. At the dev meeting, we did get some time to discuss our 'kernel nanny' plan, which will include opt-in OS-level output capturing. As part of that, the kernel will get an environment variable with a path it can log into for debugging the kernel itself. Where this goes will be up to the server - it might be written to a log file, or it might be sent straight to the terminal where you started the notebook server (the ipython kernel already logs to the terminal). Now we just need to implement that proposal! ;-) |
hmm, so the logging config is on the server side… and the env variable points to a FIFO read by the server or what? |
We haven't decided where we'll send logs yet, and it will probably be configurable on the server side. The idea is that the env var points to something that the kernel can |
sounds nice! |
@takluyver Any issues I can subscribe to, to follow along? |
So, after hearing this, my vote goes to merging this as is and then change/remove stuff in the next iteration, if that's needed.. |
There's not currently any issue or anything about this, but I'll try to remember to keep you posted about it. |
@@ -12,6 +12,7 @@ getenv_default <- function(varname, default) { | |||
#' @export | |||
jupyter_option_defaults <- list( | |||
jupyter.log_level = as.integer(getenv_default('JUPYTER_LOG_LEVEL', 1L)), | |||
jupyter.logfile = getenv_default('JUPYTER_LOGFILE'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
won’t this say “missing argument, no default”?
maybe we should change the definition of getenv_default
to function(varname, default = NULL)
?
yeah, that’s good! we can always change the |
OK, outstanding points:
|
I fixed the style fixes and the default value.
You mean as additional class methods? I still don't get how these functions would have access to the request context. |
not at all: is_silent = function(request) request$content$silent,
send_error_msg = function(request, msg) {
if (!is_silent(request)) return()
...
}, maybe we can come up with something better at another time, but this is better than inline |
So, what is worse: redefining all functions on each request or doing two object lookups for each -> Will refactor... |
you mean performance-wise? i don’t care, none of the alternatives should carry any weight. also making performance arguments before measuring is really thin ice to tread on. the point is to put as much declarative code as possible to keep the imperative part small (don’t define functions at runtime if not necessary; don’t put too much spaghetti code into one function) THIS is so yes, thanks for the last refactor! *things like Map/Reduce/apply, … are OK if they’re small, but we really do unreasonable things here. my way of attaching |
Make the execute methods smaller by removing some function definition from the method and putting them into their own methods in the executer object.
So, promoted these two functions to methods... |
Big refactoring of execute incoming... |
Executor.execute() was a long method which declared a lot of inline functions so that these functions had access of the current request. This commit adds a `current_request` field and moves the inline functions to executer methods which uses this field. This makes the execute method much shorter.
Ok, this has now a much shorter ref classes are weird: you can call functions by name, but to pass function objects, you have to specify them with |
If this is too high risk, it would be good to get everything up to 75aea9d merged. I can then add another PR just for the refactoring... |
wow cool, this is really great! i actually just wanted you to not add to the pile but instead you fixed it 😆 i’ll test it right away |
works great thanks! i only found out that my getenv_default stuff doesn’t work (apparently it’s executed on package build time or something) i’ll merge and fix this. |
ok, done: b11f259 |
This is mainly a byproduct of IRkernel/repr#21, where I wanted to see where the wrong chars come from and needed to log to a file.