confluent-kafka-python icon indicating copy to clipboard operation
confluent-kafka-python copied to clipboard

Fix docs about `logger` argument of Consumer and Producer

Open Prometheus3375 opened this issue 2 years ago • 1 comments

Description

Documentation of Kafka Client Configuration mentions keyword-only argument logger in constructors of Consumer and Producer.

image

This argument is not listed in documentation of Consumer and Producer.

In addition, the paragraph on the screenshot contains incorrect type for logger. The documentation states type logging.Handler, but in the provided example instance of class logging.Logger is passed; logging.Logger is not a subclass of logging.Handler.

As per my tests, any object with method log is accepted; this method must accept level, msg and arbitrarily many arguments.

Test code below. confluent_kafka.version() -- ('2.2.0', 33685504). confluent_kafka.libversion() -- ('2.2.0', 33685759).

import logging
import sys
from logging import LoggerAdapter, StreamHandler, getLogger
from time import sleep
from typing import Any

from confluent_kafka import Consumer


def _print(*args):
    print(*args, file=sys.stderr, flush=True)


class L:
    @staticmethod
    def log(*args, **kwargs):
        _print(args)
        _print(kwargs)


class StrictL:
    @staticmethod
    def log(level: int, msg: str, /, *args: Any):
        _print(f'{level}:\t{msg % args}')


def main():
    config = {
        'bootstrap.servers': 'localhost:9092',
        'security.protocol': 'plaintext',
        'sasl.mechanism':    'PLAIN',
        'client.id':         'test',
        'group.id':          'test',
        }

    _print('Test Logger')

    c = Consumer(config, logger=getLogger())
    c.poll(5)
    c.close()

    _print('\nTest LoggerAdapter')

    c = Consumer(config, logger=LoggerAdapter(getLogger(), {'spider': None}))
    c.poll(5)
    c.close()

    _print('\nTest logging')

    c = Consumer(config, logger=logging)
    c.poll(5)
    c.close()

    _print('\nTest L')

    c = Consumer(config, logger=L)
    c.poll(5)
    c.close()

    _print('\nTest StrictL')

    c = Consumer(config, logger=StrictL)
    c.poll(5)
    c.close()

    _print('\nTest StreamHandler')

    try:
        c = Consumer(config, logger=StreamHandler())
        c.poll(5)
    except AttributeError as e:
        _print(e.__class__.__name__, e)
    finally:
        c.close()


if __name__ == '__main__':
    main()

Prometheus3375 avatar Nov 01 '23 14:11 Prometheus3375

I agree with this issue. It looks like the following items need to be fixed.

  1. [Document] Change logger=logging.Handler to logger=logging.Logger in doc string
  2. [Document] It would be nice if you could describe all the ways to register as a logger. People seem to be asking about it repeatedly. ref
  3. [Code] When I put logger as a parameter, it would be nice to have a logger parameter member in Producer, Consumer. Right now there is only config. It looks like something could be done to fix this.
class Consumer(object):
   ...
    def __init__(self, config, logger = None): # real signature unknown; restored from __doc__
        pass
  1. [Document] It seems that it is possible to register a logger in Producer and Consumer, but it would be good to check if it is possible in other classes (ex. Admin) and write it in the documentation.

wonjerry avatar Jan 22 '24 13:01 wonjerry