🎉 Initial commit

This commit is contained in:
Marc Koch 2022-10-27 15:58:12 +02:00
commit dd7f78a900
Signed by: marc
GPG Key ID: 12406554CFB028B9
16 changed files with 435 additions and 0 deletions

165
.gitignore vendored Normal file
View File

@ -0,0 +1,165 @@
# Created by https://www.toptal.com/developers/gitignore/api/python
# Edit at https://www.toptal.com/developers/gitignore?templates=python
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# End of https://www.toptal.com/developers/gitignore/api/python

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyNamespacePackagesService">
<option name="namespacePackageFolders">
<list>
<option value="$MODULE_DIR$/tests" />
</list>
</option>
</component>
</module>

View File

@ -0,0 +1,15 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="pandas" />
</list>
</value>
</option>
</inspection_tool>
<inspection_tool class="ReassignedToPlainText" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

4
.idea/misc.xml Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (civiproxy_logs2json)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/civiproxy_logs2json.iml" filepath="$PROJECT_DIR$/.idea/civiproxy_logs2json.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

16
LICENSE Normal file
View File

@ -0,0 +1,16 @@
The MIT License (MIT)
Copyright © 2022 Marc Michalsky
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

32
README.md Normal file
View File

@ -0,0 +1,32 @@
# CiviProxy_Logs2Json
Translate a [CiviProxy](https://github.com/systopia/CiviProxy) logfile into JSON format.
## Installation
```bash
pyton3 -m pip install civiproxy_logs2json
```
## Example Usage
Pass logfile as positional argument:
```bash
cpl2j /var/www/proxy_logs/proxy.log
```
Pipe logfile into program:
```bash
cat proxy.log | cpl2j
```
Set JSON indentation to two spaces:
```bash
cat proxy.log | cpl2j -s 2
```
### Tip
Use [VisiData](https://github.com/saulpw/visidata) to explore the data in a very comfortable way:
/var/www/proxy_logs/proxy.log
```bash
cpl2j /var/www/proxy_logs/proxy.log | vd -f json
```

View File

@ -0,0 +1 @@
from .__main__ import main, translate_logfile

View File

@ -0,0 +1,62 @@
import argparse
import json
import re
import sys
from typing import TextIO
REQUEST_LINE_RE = r"^REQUEST FROM (?P<source>(\d{1,3}\.){3}\d{1,3}) ON (?P<date>\d\d\d\d-\d\d-\d\d) (?P<time>\d\d:\d\d:\d\d) -- Array$"
VALUES_LINE_RE = r"^\s{4}\[(?P<key>.*)] => (?P<value>.*)$"
CLOSING_LINE_RE = r"^\)$"
# Setup argparse
argparser = argparse.ArgumentParser(
description='Translate a CiviProxy logfile into JSON format. ')
argparser.add_argument('logfile',
help='CiviProxy logfile',
type=argparse.FileType('r', encoding='UTF-8'),
default=(None if sys.stdin.isatty() else sys.stdin))
argparser.add_argument('-i',
'--indent',
help='Print JSON with indent',
type=int,
default=4)
def main():
args = argparser.parse_args()
# Print info if no logfile is specified or passed via stdin
if not args.logfile:
print('Please specify a path to a CiviProxy logfile')
sys.exit()
# Parse logfile and print it to console
print(json.dumps(translate_logfile(args.logfile), indent=args.indent))
def translate_logfile(logfile: TextIO) -> list:
json_ = []
with logfile as file:
array = {}
for line in file:
request_line = re.search(REQUEST_LINE_RE, line)
values_line = re.search(VALUES_LINE_RE, line)
close_line = re.search(CLOSING_LINE_RE, line)
if request_line:
array["date"] = request_line.group("date")
array["time"] = request_line.group("time")
array["source"] = request_line.group("source")
elif values_line:
if values_line.group("key") == "json":
array["values"] = json.loads(values_line.group("value"))
else:
array[values_line.group("key")] = values_line.group("value")
elif close_line:
if array:
json_.append(array)
array = {}
return json_
if __name__ == '__main__':
main()

24
setup.py Normal file
View File

@ -0,0 +1,24 @@
import setuptools
with open("README.md", "r") as fh:
description = fh.read()
setuptools.setup(
name="civiproxy_logs2json",
version="1.0.0",
author="Marc Michalsky",
author_email="michalsky@forumZFD.de",
packages=["civiproxy_logs2json"],
description="Translate a CiviProxy logfile into JSON format.",
long_description=description,
long_description_content_type="text/markdown",
url="https://github.com/MarcMichalsky/civiproxy_logs2json",
license='MIT',
python_requires='>=3.8',
install_requires=[],
entry_points={
'console_scripts': [
'cpl2j = civiproxy_logs2json.__main__:main',
],
},
)

13
tests/assets/proxy.log Normal file
View File

@ -0,0 +1,13 @@
REQUEST FROM 127.0.0.1 ON 2022-10-26 11:34:23 -- Array
(
[id] => contribute/images/uploads/static/test.png
)
REQUEST FROM 127.0.0.1 ON 2022-10-26 13:32:26 -- Array
(
[json] => {"project_id":"twxxxxxxxxxxxxx","trx_id":"XXXXXXX","parent_trx_id":null,"confirmed_at":"20221026131623","purpose":"Allgemeine Spende","amount":800,"currency":"EUR","user_email":"john.doe@example.com","user_country":"DE","user_language":"de","payment_method":"paypal","donation_rhythm":"one_time","is_anonymous":0,"newsletter":0,"postinfo":0,"donation_receipt":0,"user_title":null,"user_firstname":"John","user_lastname":"Doe","user_street":null,"user_postal_code":null,"user_city":null,"user_telephone":null,"user_company":null,"user_extrafield":null,"custom_fields":{"event":""}}
[entity] => TwingleDonation
[action] => submit
[api_key] => Xxxx...
[key] => xxxx...
)

View File

@ -0,0 +1,47 @@
[
{
"date": "2022-10-26",
"time": "11:34:23",
"source": "127.0.0.1",
"id": "contribute/images/uploads/static/test.png"
},
{
"date": "2022-10-26",
"time": "13:32:26",
"source": "127.0.0.1",
"values": {
"project_id": "twxxxxxxxxxxxxx",
"trx_id": "XXXXXXX",
"parent_trx_id": null,
"confirmed_at": "20221026131623",
"purpose": "Allgemeine Spende",
"amount": 800,
"currency": "EUR",
"user_email": "john.doe@example.com",
"user_country": "DE",
"user_language": "de",
"payment_method": "paypal",
"donation_rhythm": "one_time",
"is_anonymous": 0,
"newsletter": 0,
"postinfo": 0,
"donation_receipt": 0,
"user_title": null,
"user_firstname": "John",
"user_lastname": "Doe",
"user_street": null,
"user_postal_code": null,
"user_city": null,
"user_telephone": null,
"user_company": null,
"user_extrafield": null,
"custom_fields": {
"event": ""
}
},
"entity": "TwingleDonation",
"action": "submit",
"api_key": "Xxxx...",
"key": "xxxx..."
}
]

View File

@ -0,0 +1,11 @@
import os
import json
from civiproxy_logs2json import translate_logfile
def test_translate_logfile():
with open(f"{os.path.dirname(__file__)}/assets/proxy_log.json") as json_file:
json_ = json.load(json_file)
with open(f"{os.path.dirname(__file__)}/assets/proxy.log", "r") as log_file:
json_2 = translate_logfile(log_file)
assert json_ == json_2