U
    Pe{K                     @   s  d Z ddlZddlZddlZddlmZ ddlZddlZddlm	Z	 dZ
dZedd de_ejejejejejejdZG d	d
 d
ejZG dd dejZG dd dejZG dd deZdd ZG dd dejZG dd dejZejZ G dd dejZ!G dd dej"Z#dd Z$e%dZde_&eej'eje_(dej)krRe ndZ*e+edrjt,d d!d" Z-ej).d#d$Z/e/d%kst,d&e/d$kre-ej0 ej01ej2 ed'ej3e_4ne/d(kre-e d)e_5n dS )*a  
Kivy Logging
============

By default, Kivy provides a logging system based on the standard Python
`logging <https://docs.python.org/3/library/logging.html>`_ module with
several additional features designed to be more convenient. These features
include:

 * simplied usage (single instance, simple configuration, works by default)
 * color-coded output on supported terminals
 * output to ``stderr`` by default
 * message categorization via colon separation
 * access to log history even if logging is disabled
 * built-in handling of various cross-platform considerations
 * any stray output written to ``sys.stderr`` is captured, and stored in the log
   file as a warning.

These features are configurable via the Config file or environment variables -
including falling back to only using the standard Python system.

Logger object
=============

The Kivy ``Logger`` class provides a singleton logging.logger instance.

As well as the standard logging levels (``debug``, ``info``,
``warning``, ``error`` and ``critical``), an additional ``trace`` level is
available.

Example Usage
-------------

Use the ``Logger`` as you would a standard Python logger. ::

    from kivy.logger import Logger

    Logger.info('title: This is a info message.')
    Logger.debug('title: This is a debug message.')

    try:
        raise Exception('bleh')
    except Exception:
        Logger.exception('Something happened!')

The message passed to the logger is split into two parts separated by a colon
(:). The first part is used as a title and the second part is used as the
message. This way, you can "categorize" your messages easily. ::

    Logger.info('Application: This is a test')

    # will appear as

    [INFO   ] [Application ] This is a test

You can change the logging level at any time using the ``setLevel`` method. ::

    from kivy.logger import Logger, LOG_LEVELS

    Logger.setLevel(LOG_LEVELS["debug"])

.. versionchanged:: 2.2.0

Interaction with other logging
------------------------------

The Kivy logging system will, by default, present all log messages sent from
any logger - e.g. from third-party libraries.

Additional handlers may be added.

.. warning:: Handlers that output to ``sys.stderr`` may cause loops, as stderr
   output is reported as a warning log message.

Logger Configuration
====================

Kivy Log Mode
-------------

At the highest level, Kivy's logging system is controlled by an environment
variable ``KIVY_LOG_MODE``. It may be given any of three values:
``KIVY``, ``PYTHON``, ``MIXED``

.. versionadded: 2.2.0

KIVY Mode (default)
^^^^^^^^^^^^^^^^^^^

In ``KIVY`` mode, all Kivy handlers are attached to the root logger, so all log
messages in the system are output to the Kivy log files and to the console. Any
stray output to ``sys.stderr`` is logged as a warning.

If you are writing an entire Kivy app from scratch, this is the most convenient
mode.

PYTHON Mode
^^^^^^^^^^^

In ``PYTHON`` mode, no handlers are added, and ``sys.stderr`` output is not
captured. It is left to the client to add appropriate handlers. (If none are
added, the ``logging`` module will output them to ``stderr``.)

Messages logged with ``Logger`` will be propagated to the root logger, from a
logger named ``kivy``.

If the Kivy app is part of a much larger project which has its own logging
regimen, this is the mode that gives most control.

The ``kivy.logger`` file contains a number of ``logging.handler``,
``logging.formatter``, and other helper classes to allow
users to adopt the features of Kivy logging that they like, including the
stderr redirection.

MIXED Mode
^^^^^^^^^^

In ``MIXED`` mode, handlers are added to the Kivy's ``Logger`` object directly,
and propagation is turned off. ``sys.stderr`` is not redirected.

Messages logged with Kivy's ``Logger`` will appear in the Kivy log file and
output to the Console.

However, messages logged with other Python loggers will not be handled by Kivy
handlers. The client will need to add their own.

If you like the features of Kivy ``Logger``, but are writing a Kivy app that
relies on third-party libraries that don't use colon-separation of categorise
or depend on the display of the logger name, this mode provides a compromise.

Again, the ``kivy.logger`` file contains re-usable logging features that can be
used to get the best of both systems.

Config Files
------------

In ``KIVY`` and ``MIXED`` modes, the logger handlers can be controlled via the
Kivy configuration file::

    [kivy]
    log_level = info
    log_enable = 1
    log_dir = logs
    log_name = kivy_%y-%m-%d_%_.txt
    log_maxfiles = 100

More information about the allowed values are described in the
:mod:`kivy.config` module.

In addition, the environment variables ``KIVY_NO_FILELOG`` and
``KIVY_NO_CONSOLELOG`` can be used to turn off the installation of the
corresponding handlers.


Logger History
--------------

Even if the logger is not enabled, you still have access to the last 100
LogRecords::

    from kivy.logger import LoggerHistory

    print(LoggerHistory.history)
    N)partial)platform)add_kivy_handlersColonSplittingLogRecordColoredLogRecordCOLORSConsoleHandlerfile_log_handlerFileHandleris_color_terminalKivyFormatter
LOG_LEVELSLoggerLoggerHistoryProcessingStreamUncoloredLogRecord	   TRACE)tracedebuginfowarningerrorcriticalc                   @   s@   e Zd Zg ZdZdZdZdZdd Zdd Z	d	d
 Z
dd ZdS )r
   zlog.txtN zutf-8c                 C   s   | j s
dS ddlm} |dd}t| j }|dk r:dS td dd | D }|j	d	d
 d |d| pvt
| D ]V\}}z|  W q| ttfk
r } ztd| dt|  W 5 d}~X Y q|X q|td dS )zPurge logs which exceed the maximum amount of log files,
        starting with the oldest creation timestamp (or edit-timestamp on Linux)
        Nr   ConfigkivyZlog_maxfilesz&Logger: Purge log fired. Processing...c                 S   s"   g | ]}|  r|| jfqS  )is_filestatst_ctime).0itemr   r   //tmp/pip-unpacked-wheel-xzebddm3/kivy/logger.py
<listcomp>   s    z*FileHandler.purge_logs.<locals>.<listcomp>c                 S   s   | d S )N   r   )xr   r   r$   <lambda>       z(FileHandler.purge_logs.<locals>.<lambda>)keyzLogger: Skipped file z, zLogger: Purge finished!)log_dirkivy.configr   getintpathlibPathr   r   iterdirsortlenunlinkPermissionErrorFileNotFoundErrorrepr)selfr   Zmaxfilesr+   filesfile_er   r   r$   
purge_logs   s$    
.zFileHandler.purge_logsc                 O   s(  ddl m} ddlm} |dd}|dd}tj}|rLtj	|rL|}ntj
||}tj|spt| || _|dd}tj
|||}d}	|dt|	}
tj|
sq|	d	7 }	|	d
krtdqtj|
krtjd k	rd S |
t_tjdkrtj  t|
dtjdt_td|
  d S )Nr   )strftimer   r   r+   log_namez%_z
@@NUMBER@@r&   i'  zToo many logfile, remove themNFw)encodingzLogger: Record log in %s)timer=   r,   r   getr   Zkivy_home_dirospathisabsjoinexistsmakedirsr+   replacestr	Exceptionr
   filenamefdcloseopenrA   r   r   )r7   largskwargsr=   r   r+   r>   Z_dirpatternnrM   r   r   r$   
_configure   s6    


zFileHandler._configurec                 C   sL   t jdkrd S | |}t j}d}|d|j  |||  |  d S )Nr?   z%s
z[%-7s] )r
   rN   formatwrite	levelnameflush)r7   recordmsgstreamfsr   r   r$   _write_message  s    

zFileHandler._write_messagec                 C   s   t jd krt j|g7  _d S t jdkr2g t_d S tjd krz8|   ddlm} || jdd || jdd W n: t	k
r   tjdkrtj
  dt_t d Y d S X tjrtj }| | q| | d S )	NFr   r   r   r+   r>   r?   z)Error while activating FileHandler logger)r   logfile_activatedr
   historyrN   rU   r,   r   Zadd_callbackrL   rO   	exceptionpopr^   )r7   messager   _messager   r   r$   emit)  s,    






zFileHandler.emit)__name__
__module____qualname__r`   rM   rN   r+   rA   r<   rU   r^   re   r   r   r   r$   r
      s   $#r
   c                       s4   e Zd Zg Zdd Zedd Z fddZ  ZS )r   c                 C   s   |gt jd d  t _d S )Nd   )r   r`   )r7   rc   r   r   r$   re   L  s    zLoggerHistory.emitc                 C   s   | j d d = d S N)r`   )clsr   r   r$   clear_historyO  s    zLoggerHistory.clear_historyc                    s   t t|   |   d S rj   )superr   rY   rl   r7   	__class__r   r$   rY   S  s    zLoggerHistory.flush)	rf   rg   rh   r`   re   classmethodrl   rY   __classcell__r   r   ro   r$   r   H  s
   
r   c                   @   s   e Zd ZdZdd ZdS )r   z
        Emits records to a stream (by default, stderr).

        However, if the msg starts with "stderr:" it is not formatted, but
        written straight to the stream.

        .. versionadded:: 2.2.0
    c                 C   sb   zH|j }|dd}|d dkrFt|dkrF| j|d d  W dS W n tk
r\   Y nX dS )	N:r&   r   stderr   
FT)r[   splitr2   r\   rW   rL   )r7   rZ   r[   kr   r   r$   filterb  s    
zConsoleHandler.filterN)rf   rg   rh   __doc__ry   r   r   r   r$   r   X  s   	r   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )r   z
        Stream-like object that takes each completed line written to it,
        adds a given prefix, and applies the given function to it.

        .. versionadded:: 2.2.0
    c                 C   s   d| _ || _|| _d| _d S )Nr   )bufferfuncchannelerrors)r7   r}   r|   r   r   r$   __init__y  s    zProcessingStream.__init__c                 C   sX   | j | }|   | j}| j}|d}|d d D ]}|d||f  q4|d | _ d S )Nrv   z%s: %s)r{   rY   r|   r}   rw   )r7   sfr}   linesliner   r   r$   rW     s    

zProcessingStream.writec                 C   s   d S rj   r   rn   r   r   r$   rY     s    zProcessingStream.flushc                 C   s   dS r?   r   rn   r   r   r$   isatty  s    zProcessingStream.isattyN)rf   rg   rh   rz   r   rW   rY   r   r   r   r   r$   r   q  s
   
r   c                 C   s:   t dkr6t|d kr$td|tjt|d d S )NPYTHONzLoglevel {0!r} doesn't exists)level)KIVY_LOG_MODEr   rC   AttributeErrorrV   r   setLevel)sectionr*   valuer   r   r$   logger_config_update  s    r   c                       s    e Zd ZdZ fddZ  ZS )r   z{Clones an existing logRecord, but reformats the message field
    if it contains a colon.

    .. versionadded:: 2.2.0
    c                    s   z<|j dd}t|dkr2d|d |d f }n|d }W n tk
rV   |j }Y nX t j|j|j|j|j	||j
|j|j|jd	 d S )Nrs   r&   ru   z	[%-12s]%sr   	namer   pathnamelinenor[   argsexc_infor|   sinfo)r[   rw   r2   rL   rm   r   r   levelnor   r   r   r   funcName
stack_info)r7   	logrecordpartsZnew_msgro   r   r$   r     s$    z ColonSplittingLogRecord.__init__)rf   rg   rh   rz   r   rr   r   r   ro   r$   r     s   r   c                       sv   e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZe	eee
eedZedd Zedd Z fddZ  ZS )r   zClones an existing logRecord, but reformats the levelname to add
    color, and the message to add bolding (where indicated by $BOLD
    and $RESET in the message).

    .. versionadded:: 2.2.0r   r&   ru                  z[0mz[1;%dmz[1m)r   WARNINGINFODEBUGCRITICALERRORc                 C   s   t |d| jd| jS )N$RESET$BOLD)rK   rJ   	RESET_SEQBOLD_SEQrk   rc   r   r   r$   _format_message  s      z ColoredLogRecord._format_messagec                 C   s,   || j kr(| jd| j |   | | j S |S )N   )LEVEL_COLORS	COLOR_SEQr   )rk   rX   r   r   r$   _format_levelname  s    
z"ColoredLogRecord._format_levelnamec                    sP   t  j|j|j|j|j|j|j|j|j	|j
d	 | | j| _| | j| _d S Nr   )rm   r   r   r   r   r   r[   r   r   r   r   r   rX   r   r7   r   ro   r   r$   r     s    zColoredLogRecord.__init__)rf   rg   rh   rz   BLACKREDGREENYELLOWBLUEMAGENTACYANWHITEr   r   r   r   rq   r   r   r   rr   r   r   ro   r$   r     s0   	

	r   c                       s,   e Zd ZdZedd Z fddZ  ZS )r   zwClones an existing logRecord, but reformats the message
    to remove $BOLD/$RESET markup.

    .. versionadded:: 2.2.0c                 C   s   t |ddddS )Nr   r   r   )rK   rJ   r   r   r   r$   r     s    z"UncoloredLogRecord._format_messagec                    sB   t  j|j|j|j|j|j|j|j|j	|j
d	 | | j| _d S r   )rm   r   r   r   r   r   r[   r   r   r   r   r   r   ro   r   r$   r     s    zUncoloredLogRecord.__init__)rf   rg   rh   rz   rq   r   r   rr   r   r   ro   r$   r     s   
r   c                       s2   e Zd ZdZdd fdd
Z fddZ  ZS )r   zSplit out first field in message marked with a colon,
    and either apply terminal color codes to the record, or strip
    out color markup if colored logging is not available.

    .. versionadded:: 2.2.0T	use_colorc                   s    t  j|| |rtnt| _d S rj   )rm   r   r   r   _coloring_cls)r7   r   r   rR   ro   r   r$   r     s    
zKivyFormatter.__init__c                    s   t  | t|S rj   )rm   rV   r   r   )r7   rZ   ro   r   r$   rV     s    zKivyFormatter.format)rf   rg   rh   rz   r   rV   rr   r   r   ro   r$   r     s   r   c                   C   sD   t jds<t jddks<t jddks<t jddkoBtdkS )	za Detect whether the environment supports color codes in output.

    .. versionadded:: 2.2.0
    Z
WT_SESSIONZ	COLORTERMZ	truecolorPYCHARM_HOSTED1TERM)Zrxvtzrxvt-256colorzrxvt-unicodezrxvt-unicode-256colorZxtermzxterm-256color)ZandroidZios)rD   environrC   r   r   r   r   r$   r     s    r   r   ZKIVY_NO_FILELOGZ_kivy_logging_handlerz,Not supported. Try logging.root.addHandler()c                 C   sb   |  t  tr|  t dtjkr^t }|s4d}nd}t||d}t }|| |  | dS )zJ Add Kivy-specific handlers to a logger.

    .. versionadded:: 2.2.0
    ZKIVY_NO_CONSOLELOGz[%(levelname)-7s] %(message)sz[%(levelname)-18s] %(message)sr   N)	
addHandlerr   r	   rD   r   r   r   r   setFormatter)loggerr   fmt	formatterconsoler   r   r$   r   K  s    


r   r   KIVY)r   r   MIXEDzUnknown log modert   r   F)6rz   loggingrD   sys	functoolsr   r.   r   Z
kivy.utilsr   __all__r   addLevelNamer   r   r   r   r   r   r   Handlerr
   r   StreamHandlerr   objectr   r   	LogRecordr   r   r   r   r   	Formatterr   r   	getLoggerr_   logr   r   r	   hasattrAssertionErrorr   rC   r   rootr   NOTSETr   rt   	propagater   r   r   r$   <module>   sf    &	x=





