Multiple processors registering in a single rotate file

I have a problem with my nginx + uwsgi + django website. I know that for django + uwsgi there is nothing special, there must be something with the registration module itself.

On my site, I use RotatingFileHandler to register special entries, but when uwsgi works with several working processors, today I found that several log files are changing at the same time. For example, here is a fragment of a file:

[root@speed logs]# ls -lth
total 18M
-rw-rw-rw- 1 root root  2.1M Sep 14 19:44 backend.log.7
-rw-rw-rw- 1 root root  1.3M Sep 14 19:43 backend.log.6
-rw-rw-rw- 1 root root  738K Sep 14 19:43 backend.log.3
-rw-rw-rw- 1 root root  554K Sep 14 19:43 backend.log.1
-rw-rw-rw- 1 root root 1013K Sep 14 19:42 backend.log.4
-rw-rw-rw- 1 root root  837K Sep 14 19:41 backend.log.5
-rw-rw-rw- 1 root root  650K Sep 14 19:40 backend.log.2
-rw-rw-rw- 1 root root  656K Sep 14 19:40 backend.log
-rw-r--r-- 1 root root   10M Sep 13 10:11 backend.log.8
-rw-r--r-- 1 root root     0 Aug 21 15:53 general.log
[root@speed-app logs]#

In fact, I installed the rotary file on 10 million files and up to 10 files.

I googled a lot, and many people paid attention to this earlier, it seems that the registration module itself cannot support this.

, - ConcurrentLogHandler (https://pypi.python.org/pypi/ConcurrentLogHandler/0.9.1). - ? , , , .

- uwsig ?

. Wesley

+6
2

, , python StreamHandler, uWSGI " " logrotate .

, uWSGI stdout/stderr stdout/stderr ( ), /, .

Django/uWSGI

Django settings.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'default': {
            'format': '%(asctime)s - %(process)s - %(levelname)s - %(name)s : %(message)s',
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        },
    },
    'root': {
        'handlers': ['console'],
        'level': 'DEBUG',
    },
}

-

log = logging.getLogger(__name__)
log.info("test log!")

uWSGI

$ uwsgi --http :9090 --chdir=`pwd -P` --wsgi-file=wsgi.py \
    --daemonize=test.log \  # daemonize AND set log file
    --log-maxsize=10000  \  # a 10k file rotate
    --workers=4             # start 4 workers

test.log

*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 79755)
spawned uWSGI worker 1 (pid: 79813, cores: 1)
spawned uWSGI worker 2 (pid: 79814, cores: 1)
spawned uWSGI worker 3 (pid: 79815, cores: 1)
spawned uWSGI worker 4 (pid: 79816, cores: 1)
spawned uWSGI http 1 (pid: 79817)
2015-10-12 07:55:48,458 - 79816 - INFO - testapp.views : test log!
2015-10-12 07:55:51,440 - 79813 - INFO - testapp.views : test log!
2015-10-12 07:55:51,965 - 79814 - INFO - testapp.views : test log!
2015-10-12 07:55:52,810 - 79815 - INFO - testapp.views : test log!

:

-rw-r-----   1 big  staff   1.0K Oct 12 09:56 test.log
-rw-r-----   1 big  staff    11K Oct 12 09:55 test.log.1444636554

Logrotate

, , --log-maxsize logrotate (/etc/logrotate.d/uwsgi-test-app):

/home/demo/test_django/*log {
    rotate 10
    size 10k
    daily
    compress
    delaycompress
}

, , , , , , , 10k. logrotate . .

+4

python logrotation ( gunicorn ), , , .. . !

( logging.handlers.RotatingFileHandler code)

def doRollover(self):
    self.stream.close()
    if self.backupCount > 0:
        for i in range(self.backupCount - 1, 0, -1):
            sfn = "%s.%d" % (self.baseFilename, i)
            dfn = "%s.%d" % (self.baseFilename, i + 1)
            if os.path.exists(sfn):
                if os.path.exists(dfn):
                    os.remove(dfn)
                os.rename(sfn, dfn)
        dfn = self.baseFilename + ".1"
        if os.path.exists(dfn):
            os.remove(dfn)
        # os.rename(self.baseFilename, dfn) # Intead of this
        # Do this
        shutil.copyfile(self.baseFilename, dfn)
        open(self.baseFilename, 'w').close()
    if self.encoding:
        self.stream = codecs.open(self.baseFilename, "w", self.encoding)
    else:
        self.stream = open(self.baseFilename, "w")

:

logger = logging.getLogger(logfile_name)
logfile = '{}/{}.log'.format(logfile_folder, logfile_name)
handler = RotatingFileHandler(
    logfile, maxBytes=maxBytes, backupCount=10
)
formatter = logging.Formatter(format, "%Y-%m-%d_%H:%M:%S")
formatter.converter = time.gmtime
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
logger.isEnabledFor = lambda level: True
logger.propagate = 0

logger.warning("This is a log")
0

Source: https://habr.com/ru/post/1607266/


All Articles