xmllayout2 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xmllayout2-2.0.0/.gitattributes +22 -0
- xmllayout2-2.0.0/.gitignore +103 -0
- xmllayout2-2.0.0/LICENSE +23 -0
- xmllayout2-2.0.0/PKG-INFO +57 -0
- xmllayout2-2.0.0/README.md +26 -0
- xmllayout2-2.0.0/pyproject.toml +3 -0
- xmllayout2-2.0.0/setup.cfg +29 -0
- xmllayout2-2.0.0/setup.py +43 -0
- xmllayout2-2.0.0/xmllayout2/__init__.py +0 -0
- xmllayout2-2.0.0/xmllayout2/formatters.py +96 -0
- xmllayout2-2.0.0/xmllayout2/handlers.py +33 -0
- xmllayout2-2.0.0/xmllayout2/tests/__init__.py +0 -0
- xmllayout2-2.0.0/xmllayout2/tests/test_formatters.py +119 -0
- xmllayout2-2.0.0/xmllayout2.egg-info/PKG-INFO +57 -0
- xmllayout2-2.0.0/xmllayout2.egg-info/SOURCES.txt +18 -0
- xmllayout2-2.0.0/xmllayout2.egg-info/dependency_links.txt +1 -0
- xmllayout2-2.0.0/xmllayout2.egg-info/not-zip-safe +1 -0
- xmllayout2-2.0.0/xmllayout2.egg-info/requires.txt +3 -0
- xmllayout2-2.0.0/xmllayout2.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Auto detect text files and perform LF normalization
|
|
2
|
+
* text=auto
|
|
3
|
+
|
|
4
|
+
# Custom for Visual Studio
|
|
5
|
+
*.cs diff=csharp
|
|
6
|
+
*.sln merge=union
|
|
7
|
+
*.csproj merge=union
|
|
8
|
+
*.vbproj merge=union
|
|
9
|
+
*.fsproj merge=union
|
|
10
|
+
*.dbproj merge=union
|
|
11
|
+
|
|
12
|
+
# Standard to msysgit
|
|
13
|
+
*.doc diff=astextplain
|
|
14
|
+
*.DOC diff=astextplain
|
|
15
|
+
*.docx diff=astextplain
|
|
16
|
+
*.DOCX diff=astextplain
|
|
17
|
+
*.dot diff=astextplain
|
|
18
|
+
*.DOT diff=astextplain
|
|
19
|
+
*.pdf diff=astextplain
|
|
20
|
+
*.PDF diff=astextplain
|
|
21
|
+
*.rtf diff=astextplain
|
|
22
|
+
*.RTF diff=astextplain
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
|
|
5
|
+
# C extensions
|
|
6
|
+
*.so
|
|
7
|
+
|
|
8
|
+
# Distribution / packaging
|
|
9
|
+
.Python
|
|
10
|
+
env/
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
eggs/
|
|
15
|
+
lib/
|
|
16
|
+
lib64/
|
|
17
|
+
parts/
|
|
18
|
+
sdist/
|
|
19
|
+
var/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
.installed.cfg
|
|
22
|
+
*.egg
|
|
23
|
+
|
|
24
|
+
# PyInstaller
|
|
25
|
+
# Usually these files are written by a python script from a template
|
|
26
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
27
|
+
*.manifest
|
|
28
|
+
*.spec
|
|
29
|
+
|
|
30
|
+
# Installer logs
|
|
31
|
+
pip-log.txt
|
|
32
|
+
pip-delete-this-directory.txt
|
|
33
|
+
|
|
34
|
+
# Unit test / coverage reports
|
|
35
|
+
htmlcov/
|
|
36
|
+
.tox/
|
|
37
|
+
.coverage
|
|
38
|
+
.cache
|
|
39
|
+
nosetests.xml
|
|
40
|
+
coverage.xml
|
|
41
|
+
|
|
42
|
+
# Translations
|
|
43
|
+
*.mo
|
|
44
|
+
*.pot
|
|
45
|
+
|
|
46
|
+
# Django stuff:
|
|
47
|
+
*.log
|
|
48
|
+
|
|
49
|
+
# Sphinx documentation
|
|
50
|
+
docs/_build/
|
|
51
|
+
|
|
52
|
+
# PyBuilder
|
|
53
|
+
target/
|
|
54
|
+
|
|
55
|
+
# =========================
|
|
56
|
+
# Operating System Files
|
|
57
|
+
# =========================
|
|
58
|
+
|
|
59
|
+
# OSX
|
|
60
|
+
# =========================
|
|
61
|
+
|
|
62
|
+
.DS_Store
|
|
63
|
+
.AppleDouble
|
|
64
|
+
.LSOverride
|
|
65
|
+
|
|
66
|
+
# Icon must end with two \r
|
|
67
|
+
Icon
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# Thumbnails
|
|
71
|
+
._*
|
|
72
|
+
|
|
73
|
+
# Files that might appear on external disk
|
|
74
|
+
.Spotlight-V100
|
|
75
|
+
.Trashes
|
|
76
|
+
|
|
77
|
+
# Directories potentially created on remote AFP share
|
|
78
|
+
.AppleDB
|
|
79
|
+
.AppleDesktop
|
|
80
|
+
Network Trash Folder
|
|
81
|
+
Temporary Items
|
|
82
|
+
.apdisk
|
|
83
|
+
|
|
84
|
+
# Windows
|
|
85
|
+
# =========================
|
|
86
|
+
|
|
87
|
+
# Windows image file caches
|
|
88
|
+
Thumbs.db
|
|
89
|
+
ehthumbs.db
|
|
90
|
+
|
|
91
|
+
# Folder config file
|
|
92
|
+
Desktop.ini
|
|
93
|
+
|
|
94
|
+
# Recycle Bin used on file shares
|
|
95
|
+
$RECYCLE.BIN/
|
|
96
|
+
|
|
97
|
+
# Windows Installer files
|
|
98
|
+
*.cab
|
|
99
|
+
*.msi
|
|
100
|
+
*.msm
|
|
101
|
+
*.msp
|
|
102
|
+
|
|
103
|
+
venv/
|
xmllayout2-2.0.0/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Copyright (c) 2014: Philip Jenvey, 2020-2025: Jonas Lindner
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
15
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
16
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
17
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
18
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
19
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
20
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
21
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
22
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
23
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: xmllayout2
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Formats Python log messages as log4j XMLLayout XML
|
|
5
|
+
Home-page: http://pypi.python.org/pypi/XMLLayout
|
|
6
|
+
Author: Jonas Lindner
|
|
7
|
+
Author-email: jonaslindner55@gmail.com
|
|
8
|
+
License: BSD
|
|
9
|
+
Keywords: logging log4j
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
16
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: Jython
|
|
18
|
+
Classifier: Topic :: System :: Logging
|
|
19
|
+
Description-Content-Type: text/markdown; charset=UTF-8
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Requires-Dist: pytest>=6.2.2; extra == "test"
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: keywords
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: summary
|
|
31
|
+
|
|
32
|
+
XMLLayout2 provides a Python logging Formatter that formats log messages as XML,
|
|
33
|
+
according to `log4j's [XMLLayout specification](https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/XMLLayout.html)
|
|
34
|
+
|
|
35
|
+
XMLLayout formatted log messages can be viewed and filtered within the
|
|
36
|
+
[Chainsaw](https://logging.apache.org/chainsaw/2.x) application
|
|
37
|
+
(see the example section below), part of the Java based log4j project.
|
|
38
|
+
|
|
39
|
+
This package also includes a RawSocketHandler -- like
|
|
40
|
+
logging.handler.SocketHandler, but sends the raw log message over the socket
|
|
41
|
+
instead of a pickled version. RawSocketHandler can be configured to send log
|
|
42
|
+
messages to Chainsaw directly over a socket.
|
|
43
|
+
|
|
44
|
+
For example: to forward log messages to Chainsaw, if it were listening on
|
|
45
|
+
localhost port 4448::
|
|
46
|
+
|
|
47
|
+
import logging
|
|
48
|
+
import xmllayout2
|
|
49
|
+
|
|
50
|
+
handler = xmllayout2.RawSocketHandler('localhost', 4448)
|
|
51
|
+
handler.setFormatter(xmllayout2.XMLLayout())
|
|
52
|
+
logging.root.addHandler(handler)
|
|
53
|
+
|
|
54
|
+
This is a fork of Philip Jenveys original package xmllayout. Maintained for usage in commercial projects, with supporting a variety of Python versions.
|
|
55
|
+
|
|
56
|
+
Installation via pip:
|
|
57
|
+
pip install xmllayout2
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
XMLLayout2 provides a Python logging Formatter that formats log messages as XML,
|
|
2
|
+
according to `log4j's [XMLLayout specification](https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/XMLLayout.html)
|
|
3
|
+
|
|
4
|
+
XMLLayout formatted log messages can be viewed and filtered within the
|
|
5
|
+
[Chainsaw](https://logging.apache.org/chainsaw/2.x) application
|
|
6
|
+
(see the example section below), part of the Java based log4j project.
|
|
7
|
+
|
|
8
|
+
This package also includes a RawSocketHandler -- like
|
|
9
|
+
logging.handler.SocketHandler, but sends the raw log message over the socket
|
|
10
|
+
instead of a pickled version. RawSocketHandler can be configured to send log
|
|
11
|
+
messages to Chainsaw directly over a socket.
|
|
12
|
+
|
|
13
|
+
For example: to forward log messages to Chainsaw, if it were listening on
|
|
14
|
+
localhost port 4448::
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
import xmllayout2
|
|
18
|
+
|
|
19
|
+
handler = xmllayout2.RawSocketHandler('localhost', 4448)
|
|
20
|
+
handler.setFormatter(xmllayout2.XMLLayout())
|
|
21
|
+
logging.root.addHandler(handler)
|
|
22
|
+
|
|
23
|
+
This is a fork of Philip Jenveys original package xmllayout. Maintained for usage in commercial projects, with supporting a variety of Python versions.
|
|
24
|
+
|
|
25
|
+
Installation via pip:
|
|
26
|
+
pip install xmllayout2
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[metadata]
|
|
2
|
+
name = "xmllayout2"
|
|
3
|
+
description = "Formats Python log messages as log4j XMLLayout XML"
|
|
4
|
+
version = "2.0.0"
|
|
5
|
+
author = Jonas Lindner
|
|
6
|
+
author_email = "jonaslindner55@gmail.com"
|
|
7
|
+
keywords = ['logging', 'log4j']
|
|
8
|
+
license = BSD 2-clause
|
|
9
|
+
license_file = LICENSE
|
|
10
|
+
long_description_content_type = text/markdown; charset=UTF-8
|
|
11
|
+
classifiers =
|
|
12
|
+
'Development Status :: 5 - Production/Stable',
|
|
13
|
+
'Intended Audience :: Developers',
|
|
14
|
+
'License :: OSI Approved :: BSD License',
|
|
15
|
+
'Programming Language :: Python',
|
|
16
|
+
'Programming Language :: Python :: 3',
|
|
17
|
+
'Programming Language :: Python :: Implementation :: CPython',
|
|
18
|
+
'Programming Language :: Python :: Implementation :: PyPy',
|
|
19
|
+
'Programming Language :: Python :: Implementation :: Jython',
|
|
20
|
+
'Topic :: System :: Logging'
|
|
21
|
+
|
|
22
|
+
[options.extras_require]
|
|
23
|
+
test =
|
|
24
|
+
pytest >= 6.2.2
|
|
25
|
+
|
|
26
|
+
[egg_info]
|
|
27
|
+
tag_build =
|
|
28
|
+
tag_date = 0
|
|
29
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from os import path
|
|
2
|
+
from setuptools import setup, find_packages
|
|
3
|
+
import io
|
|
4
|
+
|
|
5
|
+
version = '2.0.0'
|
|
6
|
+
|
|
7
|
+
# Just here for Python2
|
|
8
|
+
# compatibility
|
|
9
|
+
# If not needed:
|
|
10
|
+
# import setuptools
|
|
11
|
+
# if __name__ == "__main__":
|
|
12
|
+
# setuptools.setup()
|
|
13
|
+
|
|
14
|
+
here = path.abspath(path.dirname(__file__))
|
|
15
|
+
with io.open(path.join(here, 'README.md')) as f:
|
|
16
|
+
long_description = f.read()
|
|
17
|
+
|
|
18
|
+
setup(
|
|
19
|
+
name='xmllayout2',
|
|
20
|
+
version=version,
|
|
21
|
+
description="Formats Python log messages as log4j XMLLayout XML",
|
|
22
|
+
long_description=long_description,
|
|
23
|
+
classifiers=[
|
|
24
|
+
'Development Status :: 5 - Production/Stable',
|
|
25
|
+
'Intended Audience :: Developers',
|
|
26
|
+
'License :: OSI Approved :: BSD License',
|
|
27
|
+
'Programming Language :: Python',
|
|
28
|
+
'Programming Language :: Python :: 3',
|
|
29
|
+
'Programming Language :: Python :: Implementation :: CPython',
|
|
30
|
+
'Programming Language :: Python :: Implementation :: PyPy',
|
|
31
|
+
'Programming Language :: Python :: Implementation :: Jython',
|
|
32
|
+
'Topic :: System :: Logging'
|
|
33
|
+
],
|
|
34
|
+
keywords='logging log4j',
|
|
35
|
+
author='Jonas Lindner',
|
|
36
|
+
author_email='jonaslindner55@gmail.com',
|
|
37
|
+
url='http://pypi.python.org/pypi/XMLLayout',
|
|
38
|
+
license='BSD',
|
|
39
|
+
packages=find_packages(),
|
|
40
|
+
include_package_data=True,
|
|
41
|
+
zip_safe=False,
|
|
42
|
+
tests_require=['pytest'],
|
|
43
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""logging Formatters"""
|
|
2
|
+
try:
|
|
3
|
+
from cgi import escape # < Python3.7
|
|
4
|
+
except ImportError:
|
|
5
|
+
from html import escape
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
__all__ = ['XMLLayout']
|
|
9
|
+
|
|
10
|
+
# Level names differ slightly in log4j, see
|
|
11
|
+
# http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Level.html
|
|
12
|
+
LOG4J_LEVELS = dict(WARNING='WARN', CRITICAL='FATAL')
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class XMLLayout(logging.Formatter):
|
|
16
|
+
|
|
17
|
+
"""Formats log Records as XML according to the `log4j XMLLayout
|
|
18
|
+
<http://logging.apache.org/log4j/docs/api/org/apache/log4j/xml/
|
|
19
|
+
XMLLayout.html>_`
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def format(self, record):
|
|
23
|
+
"""Format the log record as XMLLayout XML"""
|
|
24
|
+
levelname = LOG4J_LEVELS.get(record.levelname, record.levelname)
|
|
25
|
+
event = dict(name=escape(record.name),
|
|
26
|
+
threadName=escape(record.threadName),
|
|
27
|
+
levelname=escape(levelname),
|
|
28
|
+
created=int(record.created * 1000))
|
|
29
|
+
|
|
30
|
+
event['message'] = LOG4J_MESSAGE % escape_cdata(record.getMessage())
|
|
31
|
+
|
|
32
|
+
# FIXME: Support an NDC somehow
|
|
33
|
+
event['ndc'] = ''
|
|
34
|
+
# ndc = self.get_ndc(record)
|
|
35
|
+
# if ndc:
|
|
36
|
+
# event['ndc'] = LOG4J_NDC % escape_cdata(ndc)
|
|
37
|
+
|
|
38
|
+
event['throwable'] = ''
|
|
39
|
+
if record.exc_info:
|
|
40
|
+
if not record.exc_text:
|
|
41
|
+
record.exc_text = self.formatException(record.exc_info)
|
|
42
|
+
event['throwable'] = (LOG4J_THROWABLE %
|
|
43
|
+
escape_cdata(record.exc_text))
|
|
44
|
+
|
|
45
|
+
location_info = dict(pathname=escape(record.pathname),
|
|
46
|
+
lineno=record.lineno,
|
|
47
|
+
module=escape(record.module), funcName='')
|
|
48
|
+
if hasattr(record, 'funcName'):
|
|
49
|
+
# >= Python 2.5
|
|
50
|
+
location_info['funcName'] = escape(record.funcName)
|
|
51
|
+
event['locationInfo'] = LOG4J_LOCATIONINFO % location_info
|
|
52
|
+
|
|
53
|
+
return LOG4J_EVENT % event
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def escape_cdata(cdata):
|
|
57
|
+
"""Escape XML CDATA content"""
|
|
58
|
+
return cdata.replace(']]>', ']]]]><![CDATA[>')
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# General logging information
|
|
62
|
+
LOG4J_EVENT = """\
|
|
63
|
+
<log4j:event logger="%(name)s"
|
|
64
|
+
timestamp="%(created)i"
|
|
65
|
+
level="%(levelname)s"
|
|
66
|
+
thread="%(threadName)s">
|
|
67
|
+
%(message)s%(ndc)s%(throwable)s%(locationInfo)s</log4j:event>
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# The actual log message
|
|
72
|
+
LOG4J_MESSAGE = """\
|
|
73
|
+
<log4j:message><![CDATA[%s]]></log4j:message>
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# log4j's 'Nested Diagnostic Context': additional, customizable information
|
|
78
|
+
# included with the log record
|
|
79
|
+
LOG4J_NDC = """\
|
|
80
|
+
<log4j:ndc><![CDATA[%s]]></log4j:ndc>
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# Exception information, if exc_info was included with the record
|
|
85
|
+
LOG4J_THROWABLE = """\
|
|
86
|
+
<log4j:throwable><![CDATA[%s]]></log4j:throwable>
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# Traceback information
|
|
91
|
+
LOG4J_LOCATIONINFO = """\
|
|
92
|
+
<log4j:locationInfo class="%(module)s"
|
|
93
|
+
method="%(funcName)s"
|
|
94
|
+
file="%(pathname)s"
|
|
95
|
+
line="%(lineno)d"/>
|
|
96
|
+
"""
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""logging Handlers"""
|
|
2
|
+
import logging.handlers
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
__all__ = ['RawSocketHandler']
|
|
6
|
+
|
|
7
|
+
PY3 = sys.version_info >= (3,)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RawSocketHandler(logging.handlers.SocketHandler):
|
|
11
|
+
"""Logging Handler that writes log records to a streaming socket.
|
|
12
|
+
|
|
13
|
+
Like ``logging.handlers.SocketHandler``, but writes the actual formatted
|
|
14
|
+
log record (not a pickled version).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def emit(self, record):
|
|
18
|
+
"""Emit a record.
|
|
19
|
+
|
|
20
|
+
Formats the record and writes it to the socket in binary format. If
|
|
21
|
+
there is an error with the socket, silently drop the packet. If there
|
|
22
|
+
was a problem with the socket, re-establishes the socket.
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
msg = self.format(record)
|
|
26
|
+
if PY3:
|
|
27
|
+
self.send(msg.encode())
|
|
28
|
+
else:
|
|
29
|
+
self.send(msg.encode('utf-8'))
|
|
30
|
+
except (KeyboardInterrupt, SystemExit):
|
|
31
|
+
raise
|
|
32
|
+
except Exception:
|
|
33
|
+
self.handleError(record)
|
|
File without changes
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
try:
|
|
4
|
+
from six import StringIO # < Python3.10
|
|
5
|
+
except ImportError:
|
|
6
|
+
from io import StringIO
|
|
7
|
+
try:
|
|
8
|
+
import xml.etree.ElementTree as ET
|
|
9
|
+
except ImportError:
|
|
10
|
+
import elementtree.ElementTree as ET
|
|
11
|
+
|
|
12
|
+
from xmllayout2 import XMLLayout
|
|
13
|
+
|
|
14
|
+
PY3 = sys.version_info >= (3,)
|
|
15
|
+
|
|
16
|
+
LOG4J_NS = 'http://jakarta.apache.org/log4j/'
|
|
17
|
+
|
|
18
|
+
log = logging.getLogger(__name__)
|
|
19
|
+
stream = StringIO()
|
|
20
|
+
handler = logging.StreamHandler(stream)
|
|
21
|
+
xmllayout = XMLLayout()
|
|
22
|
+
handler.setFormatter(xmllayout)
|
|
23
|
+
log.addHandler(handler)
|
|
24
|
+
log.setLevel(logging.DEBUG)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ElvisException(Exception):
|
|
28
|
+
def __init__(self, info):
|
|
29
|
+
self.info = info
|
|
30
|
+
|
|
31
|
+
def __str__(self):
|
|
32
|
+
return "<ElvisException: %s (TCB because he's the king baby)>" % \
|
|
33
|
+
self.info
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_xmllayout():
|
|
37
|
+
_test_output('')
|
|
38
|
+
_test_output('hello')
|
|
39
|
+
_test_output('hello world', level=logging.DEBUG)
|
|
40
|
+
_test_output('hello world!', level=logging.WARN, log4jlevel='WARN')
|
|
41
|
+
_test_output('hello, world!', level=logging.WARNING, log4jlevel='WARN')
|
|
42
|
+
_test_output('hello, world!!', level=logging.CRITICAL, log4jlevel='FATAL')
|
|
43
|
+
_test_output('<xml><something> Hi</something></xml>')
|
|
44
|
+
_test_output("""\
|
|
45
|
+
{'CONTENT_LENGTH': '0',
|
|
46
|
+
'CONTENT_TYPE': '',
|
|
47
|
+
'HTTP_ACCEPT': '*/*',
|
|
48
|
+
'HTTP_ACCEPT_ENCODING': 'gzip, deflate',
|
|
49
|
+
'HTTP_ACCEPT_LANGUAGE': 'en',
|
|
50
|
+
'HTTP_CONNECTION': 'keep-alive',
|
|
51
|
+
'HTTP_COOKIE': ''
|
|
52
|
+
'HTTP_HOST': 'bob.local:5000',
|
|
53
|
+
'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/419.2.1 (KHTML, like Gecko) Safari/419.3',
|
|
54
|
+
'PATH_INFO': '/hello',
|
|
55
|
+
'QUERY_STRING': '',
|
|
56
|
+
'REMOTE_ADDR': '192.168.1.111',
|
|
57
|
+
'REQUEST_METHOD': 'GET',
|
|
58
|
+
'SCRIPT_NAME': '',
|
|
59
|
+
'SERVER_NAME': '0.0.0.0',
|
|
60
|
+
'SERVER_PORT': '5000',
|
|
61
|
+
'SERVER_PROTOCOL': 'HTTP/1.1',
|
|
62
|
+
'paste.evalexception': <pylons.error.PylonsEvalException object at 0x8c75ccc>,
|
|
63
|
+
'wsgi.errors': <open file '<stderr>', mode 'w' at 0x81280b0>,
|
|
64
|
+
'wsgi.input': <socket._fileobject object at 0x8c7a48c length=0>,
|
|
65
|
+
'wsgi.multiprocess': False,
|
|
66
|
+
'wsgi.multithread': True,
|
|
67
|
+
'wsgi.run_once': False,
|
|
68
|
+
'wsgi.url_scheme': 'http',
|
|
69
|
+
'wsgi.version': (1, 0),}
|
|
70
|
+
""") # noqa
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_exceptions():
|
|
74
|
+
try:
|
|
75
|
+
raise ElvisException('dog')
|
|
76
|
+
except ElvisException:
|
|
77
|
+
exc_module = ''
|
|
78
|
+
if PY3:
|
|
79
|
+
exc_module = ElvisException.__module__ + '.'
|
|
80
|
+
exc_msg = ("raise ElvisException('dog')\n%sElvisException: "
|
|
81
|
+
"<ElvisException: dog (TCB because he's the king baby)>" %
|
|
82
|
+
exc_module)
|
|
83
|
+
_test_output('Elvis has left the building', exc_info=True,
|
|
84
|
+
exc_msg=exc_msg)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_exceptions_cdata():
|
|
88
|
+
exc_msg = 'Hello ]]> World!'
|
|
89
|
+
try:
|
|
90
|
+
raise ElvisException(exc_msg)
|
|
91
|
+
except ElvisException:
|
|
92
|
+
_test_output('Elvis has left the building', exc_info=True,
|
|
93
|
+
exc_msg=exc_msg)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_output():
|
|
97
|
+
output = stream.getvalue().rstrip()
|
|
98
|
+
stream.truncate(0)
|
|
99
|
+
return '<test xmlns:log4j="%s">%s</test>' % (LOG4J_NS, output)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _test_output(message, level=logging.INFO, log4jlevel=None, exc_info=None,
|
|
103
|
+
exc_msg=None):
|
|
104
|
+
if log4jlevel is None:
|
|
105
|
+
log4jlevel = logging.getLevelName(level)
|
|
106
|
+
log.log(level, message, **dict(exc_info=exc_info))
|
|
107
|
+
output = get_output()
|
|
108
|
+
tree = ET.XML(output)
|
|
109
|
+
|
|
110
|
+
event = tree.find("{%s}event" % LOG4J_NS)
|
|
111
|
+
xml_level = event.get('level')
|
|
112
|
+
assert xml_level == log4jlevel, message
|
|
113
|
+
xml_message = tree.findtext("{%s}event/{%s}message" % (LOG4J_NS, LOG4J_NS))
|
|
114
|
+
assert message == xml_message, message
|
|
115
|
+
|
|
116
|
+
if exc_info:
|
|
117
|
+
xml_exc = tree.findtext("{%s}event/{%s}throwable" % (LOG4J_NS,
|
|
118
|
+
LOG4J_NS))
|
|
119
|
+
assert exc_msg in xml_exc, message
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: xmllayout2
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Formats Python log messages as log4j XMLLayout XML
|
|
5
|
+
Home-page: http://pypi.python.org/pypi/XMLLayout
|
|
6
|
+
Author: Jonas Lindner
|
|
7
|
+
Author-email: jonaslindner55@gmail.com
|
|
8
|
+
License: BSD
|
|
9
|
+
Keywords: logging log4j
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
16
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: Jython
|
|
18
|
+
Classifier: Topic :: System :: Logging
|
|
19
|
+
Description-Content-Type: text/markdown; charset=UTF-8
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Requires-Dist: pytest>=6.2.2; extra == "test"
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: keywords
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: summary
|
|
31
|
+
|
|
32
|
+
XMLLayout2 provides a Python logging Formatter that formats log messages as XML,
|
|
33
|
+
according to `log4j's [XMLLayout specification](https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/XMLLayout.html)
|
|
34
|
+
|
|
35
|
+
XMLLayout formatted log messages can be viewed and filtered within the
|
|
36
|
+
[Chainsaw](https://logging.apache.org/chainsaw/2.x) application
|
|
37
|
+
(see the example section below), part of the Java based log4j project.
|
|
38
|
+
|
|
39
|
+
This package also includes a RawSocketHandler -- like
|
|
40
|
+
logging.handler.SocketHandler, but sends the raw log message over the socket
|
|
41
|
+
instead of a pickled version. RawSocketHandler can be configured to send log
|
|
42
|
+
messages to Chainsaw directly over a socket.
|
|
43
|
+
|
|
44
|
+
For example: to forward log messages to Chainsaw, if it were listening on
|
|
45
|
+
localhost port 4448::
|
|
46
|
+
|
|
47
|
+
import logging
|
|
48
|
+
import xmllayout2
|
|
49
|
+
|
|
50
|
+
handler = xmllayout2.RawSocketHandler('localhost', 4448)
|
|
51
|
+
handler.setFormatter(xmllayout2.XMLLayout())
|
|
52
|
+
logging.root.addHandler(handler)
|
|
53
|
+
|
|
54
|
+
This is a fork of Philip Jenveys original package xmllayout. Maintained for usage in commercial projects, with supporting a variety of Python versions.
|
|
55
|
+
|
|
56
|
+
Installation via pip:
|
|
57
|
+
pip install xmllayout2
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.gitattributes
|
|
2
|
+
.gitignore
|
|
3
|
+
LICENSE
|
|
4
|
+
README.md
|
|
5
|
+
pyproject.toml
|
|
6
|
+
setup.cfg
|
|
7
|
+
setup.py
|
|
8
|
+
xmllayout2/__init__.py
|
|
9
|
+
xmllayout2/formatters.py
|
|
10
|
+
xmllayout2/handlers.py
|
|
11
|
+
xmllayout2.egg-info/PKG-INFO
|
|
12
|
+
xmllayout2.egg-info/SOURCES.txt
|
|
13
|
+
xmllayout2.egg-info/dependency_links.txt
|
|
14
|
+
xmllayout2.egg-info/not-zip-safe
|
|
15
|
+
xmllayout2.egg-info/requires.txt
|
|
16
|
+
xmllayout2.egg-info/top_level.txt
|
|
17
|
+
xmllayout2/tests/__init__.py
|
|
18
|
+
xmllayout2/tests/test_formatters.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
xmllayout2
|