Repository: getnikola/nikola

Issue:
logging is ultra weird with DEBUG, INFO, NOTICE
Logging is kinda broken.  For example, on a pre-existing site, this happens:

```
$ nikola build
[2014-03-09T10:03:59Z] WARNING: Nikola: The HIDE_SOURCELINK option is deprecated, use SHOW_SOURCELINK instead.
…snip…
$ nikola deploy
[2014-03-09 10:05] INFO: deploy: Successful deployment
[2014-03-09 10:05] DEBUG: deploy: Problem when reading `cache/lastdeploy`: time data 'datetime.datetime(2014, 2, 23, 13, 58, 33, 178278)' does not match format '%Y-%m-%dT%H:%M:%S.%f'
```

Which is bad, because:
- DEBUG, INFO, NOTICE messages are disregarded by our standard handler, yet there is another (default?) one that takes them and prints them (notice the lack of T, Z and seconds in the timestamp)
- DEBUG messages are not meant to be shown, yet that does happen

The culprit?  Our loghandler settings (setting WARNING as the lowest level, should be INFO).  The bad thing is, those are defaults and they are in every conf.py generated to date.  We should override it with INFO there. And come up with a solution to kill off DEBUG messages once and for all.



Discussion:
Well, the 1st uses utils.LOGGER, the latter use utils.getlogger so they _are_ different loggers.

And they can be — but the DEBUG/INFO/NOTICE messages from `nikola deploy` actually go to a default handler, which makes things ugly.

no, it goes to a logger created by utils.get_logger, which is

```
def get_logger(name, handlers):
    """Get a logger with handlers attached."""
    l = logbook.Logger(name)
    for h in handlers:
        if isinstance(h, list):
            l.handlers += h
        else:
            l.handlers.append(h)
    return l
```

That code seems to be done by you  and Daniel Devine

Well, yes, it does.  Here is what happens:
- a message goes to the logger get_logger creates
- the logger has a handler that has a level of WARNING
  - if the handler sees a WARNING or higher, it prints it and all is well
  - if the handler sees a NOTICE or lower, it does not print it,
    - but something else takes over and still prints it.

```
[2014-03-09 16:50] INFO: deploy: Successful deployment
> /home/kwpolska/git/nikola/nikola/plugins/command/deploy.py(89)_execute()
-> try:
(Pdb) self.logger.debug('wat')
[2014-03-09 16:51] DEBUG: deploy: wat
(Pdb) self.logger.warning('wat')
[2014-03-09T16:51:07Z] WARNING: deploy: wat
```

There is some other handler involved.

> That code seems to be done by you and Daniel Devine

That I’m aware of.

---

I managed to find a solution:
- `handler = logbook.NullHandler(); handler.push_application()`
- ignore the WARNING setting for the stderr handler, to keep everything sane (and because hiding the lower levels usually has bad effects on the experience.)

Any issues with that?


Resolving patch:
diff --git a/nikola/plugins/loghandler/stderr.py b/nikola/plugins/loghandler/stderr.py
--- a/nikola/plugins/loghandler/stderr.py
+++ b/nikola/plugins/loghandler/stderr.py
@@ -41,7 +41,11 @@ def attach_handler(self, sender):
         conf = self.site.config.get('LOGGING_HANDLERS').get('stderr')
         if conf or os.getenv('NIKOLA_DEBUG'):
             self.site.loghandlers.append(ColorfulStderrHandler(
-                level='DEBUG' if DEBUG else conf.get('loglevel', 'WARNING').upper(),
+                # We do not allow the level to be something else than 'DEBUG'
+                # or 'INFO'  Any other level can have bad effects on the user
+                # experience and is discouraged.
+                # (oh, and it was incorrectly set to WARNING before)
+                level='DEBUG' if DEBUG or (conf.get('loglevel', 'INFO').upper() == 'DEBUG') else 'INFO',
                 format_string=u'[{record.time:%Y-%m-%dT%H:%M:%SZ}] {record.level_name}: {record.channel}: {record.message}'
             ))
 
diff --git a/nikola/utils.py b/nikola/utils.py
--- a/nikola/utils.py
+++ b/nikola/utils.py
@@ -70,9 +70,9 @@ def get_logger(name, handlers):
     l = logbook.Logger(name)
     for h in handlers:
         if isinstance(h, list):
-            l.handlers += h
+            l.handlers = h
         else:
-            l.handlers.append(h)
+            l.handlers = [h]
     return l
 
 
@@ -83,10 +83,14 @@ def get_logger(name, handlers):
 LOGGER = get_logger('Nikola', STDERR_HANDLER)
 STRICT_HANDLER = ExceptionHandler(ApplicationWarning, level='WARNING')
 
+# This will block out the default handler and will hide all unwanted
+# messages, properly.
+logbook.NullHandler().push_application()
+
 if DEBUG:
     logging.basicConfig(level=logging.DEBUG)
 else:
-    logging.basicConfig(level=logging.WARNING)
+    logging.basicConfig(level=logging.INFO)
 
 
 def req_missing(names, purpose, python=True, optional=False):


Test patch: