Allow the caller to override the logger used.

We already have a logger associated with the client, and this makes it
easier to track which client is doing what when the logs are aggregated
on a log server.
Reduce log verbosity by making individual lines more useful

This makes it easier to match requests and responses when the logs are
aggregated on a log server.
Split debug logging into multiple loglevels

The getEffectiveLevel check is not actually necessary, the logger
already performs an isEnabledFor check when you use the
loglevel-specific methods (see Logger in python's logging module).

This also breaks DEBUG into two levels, INFO (for the request-response
cycle) and DEBUG (for the protocol-specific messages and pings).