본문 바로가기

개발하자

UTF-8 파이썬 로깅에서는 어떻게?

반응형

UTF-8 파이썬 로깅에서는 어떻게?

파이썬의 로깅 패키지를 사용하여 UTF-8 인코딩된 문자열을 파일에 기록하려고 합니다. 장난감의 예로:

import logging

def logging_test():
    handler = logging.FileHandler("/home/ted/logfile.txt", "w",
                                  encoding = "UTF-8")
    formatter = logging.Formatter("%(message)s")
    handler.setFormatter(formatter)
    root_logger = logging.getLogger()
    root_logger.addHandler(handler)
    root_logger.setLevel(logging.INFO)

    # This is an o with a hat on it.
    byte_string = '\xc3\xb4'
    unicode_string = unicode("\xc3\xb4", "utf-8")

    print "printed unicode object: %s" % unicode_string

    # Explode
    root_logger.info(unicode_string)

if __name__ == "__main__":
    logging_test()

이것은 logging.info () 통화에서 UnicodeDecodeError와 함께 폭발적으로 증가합니다.

하위 레벨에서 파이썬의 로깅 패키지는 코덱 패키지를 사용하여 로그 파일을 열고, "UTF-8" 인수를 인코딩으로 전달한다. 그것도 좋고 좋지만 유니코드 개체 대신 바이트 문자열을 파일에 쓰려다 폭발한다. 기본적으로 Python은 다음과 같은 작업을 수행합니다:

file_handler.write(unicode_string.encode("UTF-8"))

언제 이렇게 해야 하나요:

file_handler.write(unicode_string)

파이썬의 버그인가요, 아니면 제가 미친 약을 먹고 있는 건가요? FWIW, 이것은 재고 파이썬 2.6 설치입니다.




시도해 보십시오:

import logging

def logging_test():
    log = open("./logfile.txt", "w")
    handler = logging.StreamHandler(log)
    formatter = logging.Formatter("%(message)s")
    handler.setFormatter(formatter)
    root_logger = logging.getLogger()
    root_logger.addHandler(handler)
    root_logger.setLevel(logging.INFO)

    # This is an o with a hat on it.
    byte_string = '\xc3\xb4'
    unicode_string = unicode("\xc3\xb4", "utf-8")

    print "printed unicode object: %s" % unicode_string

    # Explode
    root_logger.info(unicode_string.encode("utf8", "replace"))


if __name__ == "__main__":
    logging_test()

utf-8 인코딩으로 파일을 열기 위해 codecs.open을 사용해야 할 것이라고 기대했지만 이와 같이 작동하기 때문에 기본값이거나 다른 작업이 여기서 진행되고 있습니다.




최신 Python 2.6이 나왔기 때문에 일부 Unicode 버그가 발견되어 수정되었습니다. 예를 들어, Ubuntu Jaunty 시스템에서 로그 파일 이름에서 '/home/ted/' 접두사만 제거하고 복사하여 붙여넣은 스크립트를 실행했습니다. 결과(단말기 창에서 복사하여 붙여넣기):

vinay@eta-jaunty:~/projects/ scratch$ python --version
파이썬 2.6.2
vinay@eta-jaunty:~/ projects/ scratch$ python utest.py 
인쇄된 유니코드 개체: o
vinay@eta-jaunty:~/ projects/ scratch$ 고양이 로그 파일.txt 
오
vinay@eta-jaunty:~/projects/scratch$

Windows 상자의 경우:

C:\temp>python --version
파이썬 2.6.2

C:\temp>pythonutest.파이
인쇄된 유니코드 개체: o

그리고 파일 내용:

alt text

이것은 레나트 레지브로가 왜 그것을 재현하지 못했는지도 설명해줄 수 있다.




문제를 제대로 이해했다면 다음과 같은 작업을 수행할 때 시스템에 동일한 문제가 발생할 것입니다:

str(u'ô')

를 통해 모듈의 함수에서 로케일 인식 분기를 활성화하기 전에는 유닉스의 로케일 인코딩에 대한 자동 인코딩이 작동하지 않을 것으로 생각합니다. 이 파일은 일반적으로 에 있으며, 어쨌든 검사할 가치가 있다. AFAIK, 로케일 인식은 기본적으로 비활성화되어 있습니다(Python 2.6 설치에 해당됨).

선택 사항은 다음과 같습니다:

  • 유니코드 문자열을 바이트로 인코딩하거나 코드에서 올바른 방법을 찾을 수 있도록 시스템에서 합니다(사이트별 구성이 필요합니다)
  • 코드의 유니코드 문자열을 인코딩하고 바이트만 출력합니다

Ian Bicking의 글과 관련 링크도 참조.




다음과 같은 코드가 있습니다:

raise Exception(u'щ')

원인:

  File "/usr/lib/python2.7/logging/__init__.py", line 467, in format
    s = self._fmt % record.__dict__
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)

이것은 형식 문자열이 바이트 문자열인 반면 일부 형식 문자열 인수가 ASC가 아닌 유니코드 문자열이기 때문에 발생합니다II 문자:

>>> "%(message)s" % {'message': Exception(u'\u0449')}
*** UnicodeEncodeError: 'ascii' codec can't encode character u'\u0449' in position 0: ordinal not in range(128)

포맷 문자열 유니코드를 만들면 다음과 같은 문제가 해결됩니다:

>>> u"%(message)s" % {'message': Exception(u'\u0449')}
u'\u0449'

따라서 로깅 구성에서 모든 형식 문자열 유니코드를 만듭니다:

'formatters': {
    'simple': {
        'format': u'%(asctime)-s %(levelname)s [%(name)s]: %(message)s',
        'datefmt': '%Y-%m-%d %H:%M:%S',
    },
 ...

그리고 유니코드 형식 문자열을 사용하도록 기본 형식을 패치합니다:

logging._defaultFormatter = logging.Formatter(u"%(message)s")



파이썬3에서 장고를 실행하는데 비슷한 문제가 있었다: 나의 로거는 움라우트(äöü ß)를 만나 죽었지만, 그 외에는 아무 이상이 없었다. 나는 많은 결과를 살펴 보았는데 아무 것도 작동하지 않았다. 나는 노력했다.

import locale; 
if locale.getpreferredencoding().upper() != 'UTF-8': 
    locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') 

제가 위에 댓글을 통해서. 그것은 효과가 없었다. 현재 로케일을 보니 미친 ANSI가 생겼고, 이는 기본적으로 "ASCII"를 의미하는 것으로 밝혀졌다. 그것 때문에 나는 완전히 방향을 잘못 잡았다.

로깅 형식 문자열을 유니코드로 변경해도 도움이 되지 않습니다. 스크립트의 시작 부분에 마법 부호화 주석을 설정해도 도움이 되지 않습니다. 보낸 사람의 메시지에 문자 집합을 설정하는 것은 도움이 되지 않았습니다(HTTP 요청에서 문자가 온 것).

파일 핸들러의 인코딩을 의 UTF-8로 설정하는 것이 DID 작업이었다. 아무것도 설정하지 않았기 때문에 기본값은 다음과 같다. 결국 ASCII(또는 ASCII)가 되는 것으로 보입니다. ASCII-KEY(ASS-KEY)

    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.handlers.TimedRotatingFileHandler',
            'encoding': 'UTF-8', # <-- That was missing.
            ....
        },
    },



조금 늦었지만 utf-8 로그인을 매우 쉽게 설정할 수 있는 이 게시물을 우연히 발견했습니다

여기 게시물에 대한 링크가 있습니다

또는 여기 코드:

root_logger= logging.getLogger()
root_logger.setLevel(logging.DEBUG) # or whatever
handler = logging.FileHandler('test.log', 'w', 'utf-8') # or whatever
formatter = logging.Formatter('%(name)s %(message)s') # or whatever
handler.setFormatter(formatter) # Pass handler as a parameter, not assign
root_logger.addHandler(handler)



파이썬 3.10에서 유니코드 문자(내 경우에는 그리스 문자)를 추가하여 기록할 수 있었다.

작은 예:

import logging
import sys

if __name__ == "__main__":
    logging.basicConfig(filename="log.log", filemode="w", level=logging.DEBUG, encoding="utf-8")
    root = logging.getLogger()
    root.setLevel(logging.DEBUG)
    handler = logging.StreamHandler(sys.stdout)
    handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter(" %(levelname)s - %(message)s")  # %(asctime)s - %(name)s -
    handler.setFormatter(formatter)
    root.addHandler(handler)
    logging.debug("Γεια σου μαρία")



python 스크립트를 실행하기 전에 python 3.7 이상을 사용하는 경우 환경 변수 PythonUTF8을 1로 설정합니다

예를 들어 리눅스를 사용하는 경우:

export PYTHONUTF8=1

파워셸:

$env:PYTHONUTF8 = "1"

Windows 명령줄:

set PYTHONUTF8=1

그럼 파이썬 스크립트를 실행하세요.


반응형