3
d8                 @   s   d Z ddlmZ dZdZdgZddlZddlZddlm	Z	 ddl
mZ dd	lmZ yddlZW n ek
rv   dZY nX dd
lmZ dZG dd deZddlZ
ee
j_dS )a   cloghandler.py:  A smart replacement for the standard RotatingFileHandler

ConcurrentRotatingFileHandler:  This class is a log handler which is a drop-in
replacement for the python standard log handler 'RotateFileHandler', the primary
difference being that this handler will continue to write to the same file if
the file cannot be rotated for some reason, whereas the RotatingFileHandler will
strictly adhere to the maximum file size.  Unfortunately, if you are using the
RotatingFileHandler on Windows, you will find that once an attempted rotation
fails, all subsequent log messages are dropped.  The other major advantage of
this module is that multiple processes can safely write to a single log file.

To put it another way:  This module's top priority is preserving your log
records, whereas the standard library attempts to limit disk usage, which can
potentially drop log messages. If you are trying to determine which module to
use, there are number of considerations: What is most important: strict disk
space usage or preservation of log messages? What OSes are you supporting? Can
you afford to have processes blocked by file locks?

Concurrent access is handled by using file locks, which should ensure that log
messages are not dropped or clobbered. This means that a file lock is acquired
and released for every log message that is written to disk. (On Windows, you may
also run into a temporary situation where the log file must be opened and closed
for each log message.) This can have potentially performance implications. In my
testing, performance was more than adequate, but if you need a high-volume or
low-latency solution, I suggest you look elsewhere.

See the README file for an example usage of this module.

    )rangez6$Id: cloghandler.py 6175 2009-11-02 18:40:35Z lowell $zLowell AllemanConcurrentRotatingFileHandlerN)randint)Handler)BaseRotatingHandler)SoftFileLockFc               @   sj   e Zd ZdZdddZd	d
 Zdd Zdd Zdd Zdd Z	dd Z
dd Zdd Zdd Zdd ZdS )r   a
  
    Handler for logging to a set of files, which switches from one file to the
    next when the current file reaches a certain size. Multiple processes can
    write to the log file concurrently, but this may mean that the file will
    exceed the given size.
    ar   NTFc       	      C   s   t jj|sHts"t jj|d  r0t jj|}n|sHddlm} |d ytj	| ||| W n( t
k
r   tj	| || || _Y nX d| _|| _|| _d| | _t| j| _|r| j| _dS )a
  
        Open the specified file and use it as the stream for logging.

        By default, the file grows indefinitely. You can specify particular
        values of maxBytes and backupCount to allow the file to rollover at
        a predetermined size.

        Rollover occurs whenever the current log file is nearly maxBytes in
        length. If backupCount is >= 1, the system will successively create
        new files with the same pathname as the base file, but with extensions
        ".1", ".2" etc. appended to it. For example, with a backupCount of 5
        and a base file name of "app.log", you would get "app.log",
        "app.log.1", "app.log.2", ... through to "app.log.5". The file being
        written to is always "app.log" - when it gets filled up, it is closed
        and renamed to "app.log.1", and if files "app.log.1", "app.log.2" etc.
        exist, then they are renamed to "app.log.2", "app.log.3" etc.
        respectively.

        If maxBytes is zero, rollover never occurs.

        On Windows, it is not possible to rename a file that is currently opened
        by another process.  This means that it is not possible to rotate the
        log files if multiple processes is using the same log file.  In this
        case, the current log file will continue to grow until the rotation can
        be completed successfully.  In order for rotation to be possible, all of
        the other processes need to close the file first.  A mechanism, called
        "degraded" mode, has been created for this scenario.  In degraded mode,
        the log file is closed after each log message is written.  So once all
        processes have entered degraded mode, the next rotate log attempt should
        be successful and then normal logging can be resumed.

        This log handler assumes that all concurrent processes logging to a
        single file will are using only this class, and that the exact same
        parameters are provided to each instance of this class.  If, for
        example, two different processes are using this class, but with
        different values for 'maxBytes' or 'backupCount', then odd behavior is
        expected. The same is true if this class is used by one application, but
        the RotatingFileHandler is used by another.

        NOTE:  You should always provide 'filename' as an absolute path, since
        this class will need to re-open the file during rotation. If your
        application call os.chdir() then subsequent log files could be created
        in the wrong directory.
        r   )warnzThe given 'filename' should be an absolute path.  If your application calls os.chdir(), your logs may get messed up. Use 'supress_abs_warn=True' to hide this message.Fz%s.lockN)ospathisabsFORCE_ABSOLUTE_PATHsplitabspathwarningsr	   r   __init__	TypeErrorencoding_rotateFailedmaxBytesbackupCount	lock_filer   stream_lock_degrade_debug_degrade)	selffilenamemoder   r   r   debugZsupress_abs_warnr	    r   =/tmp/pip-build-7vycvbft/nipype/nipype/external/cloghandler.pyr   K   s&    B
z&ConcurrentRotatingFileHandler.__init__c             C   s.   | j rtj| j|| j | _nt| j|| _d S )N)r   codecsopenbaseFilenamestream)r   r   r   r   r    	_openFile   s    z'ConcurrentRotatingFileHandler._openFilec             C   s,   t j|  | jj  | jjr(| j| j dS )z`Acquire thread and file locks. Also re-opening log file when running
        in 'degraded' mode.N)r   acquirer   r$   closedr%   r   )r   r   r   r    r&      s    

z%ConcurrentRotatingFileHandler.acquirec             C   st   zPy&| j js&| j j  | jr&| j j  W n$ tk
rL   | jrH| j j  Y nX W dz| jj  W dtj|  X X dS )zgRelease file and thread locks. Flush stream and take care of closing
        stream in 'degraded' mode.N)	r$   r'   flushr   closeIOErrorr   releaser   )r   r   r   r    r+      s    
z%ConcurrentRotatingFileHandler.releasec             C   s*   | j js| j j  | j j  tj|  dS )z$
        Closes the stream.
        N)r$   r'   r(   r)   r   )r   r   r   r    r)      s    

z#ConcurrentRotatingFileHandler.closec             C   s   dS )a  flush():  Do nothing.

        Since a flush is issued in release(), we don't do it here. To do a flush
        here, it would be necessary to re-lock everything, and it is just easier
        and cleaner to do it all in release(), rather than requiring two lock
        ops per handle() call.

        Doing a flush() here would also introduces a window of opportunity for
        another process to write to the log file in between calling
        stream.write() and stream.flush(), which seems like a bad thing.Nr   )r   r   r   r    r(      s    z#ConcurrentRotatingFileHandler.flushc             G   s   || _ ~~dS )z%Set degrade mode or not.  Ignore msg.N)r   )r   degrademsgargsr   r   r    r      s    z&ConcurrentRotatingFileHandler._degradec             G   sZ   |r.| j sVtjjdtj || f  d| _ n(| j rVtjjdtj || f  d| _ dS )zsA more colorful version of _degade(). (This is enabled by passing
        "debug=True" at initialization).
        z'Degrade mode - ENTERING - (pid=%d)  %s
Tz(Degrade mode - EXITING  - (pid=%d)   %s
FN)r   sysstderrwriter
   getpid)r   r,   r-   r.   r   r   r    r      s    z,ConcurrentRotatingFileHandler._degrade_debugc             C   sb  | j dkr"| jj  | jd dS | jj  z d}x*| sHtjj|r^d| jtddf }q6W ytj	| j| W n2 t
tfk
r   tj d }| jdd| dS X xjt| j d ddD ]T}d	| j|f }d	| j|d f }tjj|rtjj|rtj| tj	|| qW | jd
 }tjj|r4tj| tj	|| | jdd W d| j| j X dS )z<
        Do a rollover, as described in __init__().
        r   wNz%s.rotate.%08di   Tz*rename failed.  File in use?  exception=%sz%s.%dz.1FzRotation completed)r   r$   r)   r%   r
   r   existsr#   r   renamer*   OSErrorr/   exc_infor   r   remover   )r   Ztmpname	exc_valueisfndfnr   r   r    
doRollover   s:    




	


z(ConcurrentRotatingFileHandler.doRolloverc             C   s,   ~| j  r(| jj  | j| j | j  S dS )a   
        Determine if rollover should occur.

        For those that are keeping track. This differs from the standard
        library's RotatingLogHandler class. Because there is no promise to keep
        the file size under maxBytes we ignore the length of the current record.
        F)_shouldRolloverr$   r)   r%   r   )r   recordr   r   r    shouldRollover*  s    
z,ConcurrentRotatingFileHandler.shouldRolloverc             C   sV   | j dkrRy| jjdd W n tk
r0   dS X | jj | j krFdS | jdd dS )Nr      TFz(Rotation done or not needed at this time)r   r$   seekr*   tellr   )r   r   r   r    r@   <  s    
z-ConcurrentRotatingFileHandler._shouldRollover)r   r   r   NTF)__name__
__module____qualname____doc__r   r%   r&   r+   r)   r(   r   r   r?   rB   r@   r   r   r   r    r   C   s"        
V		2)rI   builtinsr   __version__
__author____all__r
   r/   randomr   loggingr   logging.handlersr   r!   ImportErrorZfilelockr   r   r   handlersr   r   r   r    <module>)   s(   
  
