# Secure Logger
[![FullStackWithLawrence](https://a11ybadges.com/badge?text=FullStackWithLawrence&badgeColor=orange&logo=youtube&logoColor=282828)](https://www.youtube.com/@FullStackWithLawrence)
[![Python](https://a11ybadges.com/badge?logo=python)](https://www.python.org/)<br>
[![12-Factor](https://img.shields.io/badge/12--Factor-Compliant-green.svg)](https://github.com/lpm0073/secure-logger/raw/main/doc/Twelve_Factor_Methodology.md)
[![Unit Tests](https://github.com/FullStackWithLawrence/secure-logger/actions/workflows/tests.yml/badge.svg)](https://github.com/FullStackWithLawrence/secure-logger/actions)
![GHA pushMain Status](https://img.shields.io/github/actions/workflow/status/FullStackWithLawrence/secure-logger/pushMain.yml?branch=main)
![Auto Assign](https://github.com/FullStackwithLawrence/secure-logger/actions/workflows/auto-assign.yml/badge.svg)[![Source
code](https://img.shields.io/static/v1?logo=github&label=Git&style=flat-square&color=orange&message=Source%20code)](https://github.com/FullStackWithLawrence/secure-logger)
[![Release Notes](https://img.shields.io/github/release/FullStackWithLawrence/secure-logger)](https://github.com/FullStackWithLawrence/secure-logger/releases)
[![PyPI
releases](https://img.shields.io/pypi/v/secure-logger?logo=python&logoColor=white)](https://pypi.org/project/secure-logger)
[![License: AGPL
v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
[![hack.d Lawrence
McDaniel](https://img.shields.io/badge/hack.d-Lawrence%20McDaniel-orange.svg)](https://lawrencemcdaniel.com)
A Python decorator to generate redacted and nicely formatted log
entries. Works on all callables: class, class methods, Python module
functions. Recursively redacts Python dictionary key values based on a
customizable list of case-insensitive keys. Prevents your sensitive
application data like cloud provider key-pairs from leaking into your
application logs.
## Installation
```bash
pip install secure-logger
```
## Usage
### As a decorator
```python
from secure_logger.decorators import secure_logger
import logging
logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
class Foo(object):
@secure_logger(log_level='INFO')
def bar(self, dict_data, list_data):
pass
# call your method, passing some sensitive data
dict_data = {
"not_a_sensitive_key": "you-can-see-me",
"aws-access-key-id": "i-am-hidden",
"aws-secret-access-key": "so-am-i",
}
list_data = ["foo", "bar"]
foo = Foo()
foo.bar(dict_data=dict_data, list_data=list_data)
```
Log output:
```console
INFO:secure_logger: __main__.bar() ['<__main__.Foo object at 0x103474ac0>'] keyword args: {
"dict_data": {
"not_a_sensitive_key": "you-can-see-me",
"aws-access-key-id": "*** -- secure_logger() -- ***",
"aws-secret-access-key": "*** -- secure_logger() -- ***"
},
"list_data": [
"foo",
"bar"
]
```
### As library functions
```python
from secure_logger.masked_dict import masked_dict, masked_dict2str
dict_data = {
'not_a_sensitive_key': 'you-can-see-me',
'aws-access-key_id': conf.AWS_ACCESS_KEY_ID,
'aws-secret-access-key': conf.AWS_SECRET_ACCESS_KEY
}
print(masked_dict2str(dict_data))
```
Output:
```bash
{
"not_a_sensitive_key": "you-can-see-me",
"aws-access-key-id": "*** -- secure_logger() -- ***",
"aws-secret-access-key": "*** -- secure_logger() -- ***"
}
```
## Configuration
secure_logger accepts optional parameters which you can configure as either bash environment variables or with a .env file placed in the root of your project
- **SECURE_LOGGER_SENSITIVE_KEYS**: a Python list of dictionary keys. Not case sensitive.
- **SECURE_LOGGER_REDACTION_MESSAGE**: a string value that will replace the sensitive key values
- **SECURE_LOGGER_INDENTATION**: number of characters to indent JSON string output when logging output
- **SECURE_LOGGER_LOG_LEVEL**: the level at which secure_logger generates log entries. One of: 'CRITICAL', 'FATAL', 'ERROR', 'WARN', 'WARNING', 'INFO', 'DEBUG'
Additionally, you can override individual invocations of the decorator with custom parameters:
```python
class MyClass():
@secure_logger(log_level='DEBUG', sensitive_keys=["password", "apikey", "crown_jewels"], message="*** -- TOP SECRET -- ***", indent=4)
def another_function(self, password: str, apikey: str, crown_jewels: List(dict)):
pass
```
## Configuration Defaults
```python
SECURE_LOGGER_REDACTION_MESSAGE = "*** -- secure_logger() -- ***"
SECURE_LOGGER_INDENTATION = 4
SECURE_LOGGER_SENSITIVE_KEYS = [
"password",
"token",
"client_id",
"client_secret",
"Authorization",
"secret",
"access_key_id",
"secret_access_key",
"access-key-id",
"secret-access-key",
"aws_access_key_id",
"aws_secret_access_key",
"aws-access-key-id",
"aws-secret-access-key",
]
SECURE_LOGGER_LOG_LEVEL = 'DEBUG'
```
## Contributing
Pull requests are welcomed and encouraged!
- This project uses an automated [Pull Request](.github/workflows/pullRequestController.yml) CI/CD process.
- This project conforms to [12-Factor Methodology](https://github.com/lpm0073/secure-logger/raw/main/doc/Twelve_Factor_Methodology.md).
- This project uses [Semantic Versioning](https://github.com/lpm0073/secure-logger/raw/main/doc/SEMANTIC_VERSIONING.md) which requires that git commit messages follow strict (but easy to learn) formatting rules.
Contact: [Lawrence McDaniel](https://lawrencemcdaniel.com/contact).
Raw data
{
"_id": null,
"home_page": "https://github.com/FullStackWithLawrence/secure-logger",
"name": "secure-logger",
"maintainer": "Lawrence McDaniel",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "lpm0073@gmail.com",
"keywords": "logging,security,redaction",
"author": "Lawrence McDaniel",
"author_email": "lpm0073@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/46/0a/37c7d4b1cd97f3773ab36c29f2688f638de828cf88ee66136a480e6daefa/secure-logger-0.2.0.tar.gz",
"platform": "any",
"description": "# Secure Logger\n\n[![FullStackWithLawrence](https://a11ybadges.com/badge?text=FullStackWithLawrence&badgeColor=orange&logo=youtube&logoColor=282828)](https://www.youtube.com/@FullStackWithLawrence)\n[![Python](https://a11ybadges.com/badge?logo=python)](https://www.python.org/)<br>\n[![12-Factor](https://img.shields.io/badge/12--Factor-Compliant-green.svg)](https://github.com/lpm0073/secure-logger/raw/main/doc/Twelve_Factor_Methodology.md)\n[![Unit Tests](https://github.com/FullStackWithLawrence/secure-logger/actions/workflows/tests.yml/badge.svg)](https://github.com/FullStackWithLawrence/secure-logger/actions)\n![GHA pushMain Status](https://img.shields.io/github/actions/workflow/status/FullStackWithLawrence/secure-logger/pushMain.yml?branch=main)\n![Auto Assign](https://github.com/FullStackwithLawrence/secure-logger/actions/workflows/auto-assign.yml/badge.svg)[![Source\ncode](https://img.shields.io/static/v1?logo=github&label=Git&style=flat-square&color=orange&message=Source%20code)](https://github.com/FullStackWithLawrence/secure-logger)\n[![Release Notes](https://img.shields.io/github/release/FullStackWithLawrence/secure-logger)](https://github.com/FullStackWithLawrence/secure-logger/releases)\n[![PyPI\nreleases](https://img.shields.io/pypi/v/secure-logger?logo=python&logoColor=white)](https://pypi.org/project/secure-logger)\n[![License: AGPL\nv3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)\n[![hack.d Lawrence\nMcDaniel](https://img.shields.io/badge/hack.d-Lawrence%20McDaniel-orange.svg)](https://lawrencemcdaniel.com)\n\nA Python decorator to generate redacted and nicely formatted log\nentries. Works on all callables: class, class methods, Python module\nfunctions. Recursively redacts Python dictionary key values based on a\ncustomizable list of case-insensitive keys. Prevents your sensitive\napplication data like cloud provider key-pairs from leaking into your\napplication logs.\n\n## Installation\n\n```bash\npip install secure-logger\n```\n\n## Usage\n\n### As a decorator\n\n```python\nfrom secure_logger.decorators import secure_logger\nimport logging\n\nlogging.getLogger(__name__)\nlogging.basicConfig(level=logging.INFO)\n\nclass Foo(object):\n @secure_logger(log_level='INFO')\n def bar(self, dict_data, list_data):\n pass\n\n# call your method, passing some sensitive data\ndict_data = {\n \"not_a_sensitive_key\": \"you-can-see-me\",\n \"aws-access-key-id\": \"i-am-hidden\",\n \"aws-secret-access-key\": \"so-am-i\",\n}\nlist_data = [\"foo\", \"bar\"]\nfoo = Foo()\nfoo.bar(dict_data=dict_data, list_data=list_data)\n```\n\nLog output:\n\n```console\nINFO:secure_logger: __main__.bar() ['<__main__.Foo object at 0x103474ac0>'] keyword args: {\n \"dict_data\": {\n \"not_a_sensitive_key\": \"you-can-see-me\",\n \"aws-access-key-id\": \"*** -- secure_logger() -- ***\",\n \"aws-secret-access-key\": \"*** -- secure_logger() -- ***\"\n },\n \"list_data\": [\n \"foo\",\n \"bar\"\n ]\n```\n\n### As library functions\n\n```python\nfrom secure_logger.masked_dict import masked_dict, masked_dict2str\n\ndict_data = {\n 'not_a_sensitive_key': 'you-can-see-me',\n 'aws-access-key_id': conf.AWS_ACCESS_KEY_ID,\n 'aws-secret-access-key': conf.AWS_SECRET_ACCESS_KEY\n}\nprint(masked_dict2str(dict_data))\n```\n\nOutput:\n\n```bash\n{\n \"not_a_sensitive_key\": \"you-can-see-me\",\n \"aws-access-key-id\": \"*** -- secure_logger() -- ***\",\n \"aws-secret-access-key\": \"*** -- secure_logger() -- ***\"\n}\n```\n\n## Configuration\n\nsecure_logger accepts optional parameters which you can configure as either bash environment variables or with a .env file placed in the root of your project\n\n- **SECURE_LOGGER_SENSITIVE_KEYS**: a Python list of dictionary keys. Not case sensitive.\n- **SECURE_LOGGER_REDACTION_MESSAGE**: a string value that will replace the sensitive key values\n- **SECURE_LOGGER_INDENTATION**: number of characters to indent JSON string output when logging output\n- **SECURE_LOGGER_LOG_LEVEL**: the level at which secure_logger generates log entries. One of: 'CRITICAL', 'FATAL', 'ERROR', 'WARN', 'WARNING', 'INFO', 'DEBUG'\n\nAdditionally, you can override individual invocations of the decorator with custom parameters:\n\n```python\nclass MyClass():\n\n @secure_logger(log_level='DEBUG', sensitive_keys=[\"password\", \"apikey\", \"crown_jewels\"], message=\"*** -- TOP SECRET -- ***\", indent=4)\n def another_function(self, password: str, apikey: str, crown_jewels: List(dict)):\n pass\n```\n\n## Configuration Defaults\n\n```python\nSECURE_LOGGER_REDACTION_MESSAGE = \"*** -- secure_logger() -- ***\"\nSECURE_LOGGER_INDENTATION = 4\nSECURE_LOGGER_SENSITIVE_KEYS = [\n \"password\",\n \"token\",\n \"client_id\",\n \"client_secret\",\n \"Authorization\",\n \"secret\",\n \"access_key_id\",\n \"secret_access_key\",\n \"access-key-id\",\n \"secret-access-key\",\n \"aws_access_key_id\",\n \"aws_secret_access_key\",\n \"aws-access-key-id\",\n \"aws-secret-access-key\",\n]\nSECURE_LOGGER_LOG_LEVEL = 'DEBUG'\n```\n\n## Contributing\n\nPull requests are welcomed and encouraged!\n\n- This project uses an automated [Pull Request](.github/workflows/pullRequestController.yml) CI/CD process.\n- This project conforms to [12-Factor Methodology](https://github.com/lpm0073/secure-logger/raw/main/doc/Twelve_Factor_Methodology.md).\n- This project uses [Semantic Versioning](https://github.com/lpm0073/secure-logger/raw/main/doc/SEMANTIC_VERSIONING.md) which requires that git commit messages follow strict (but easy to learn) formatting rules.\n\nContact: [Lawrence McDaniel](https://lawrencemcdaniel.com/contact).\n",
"bugtrack_url": null,
"license": "AGPLv3",
"summary": "A decorator to generate redacted and nicely formatted log entries",
"version": "0.2.0",
"project_urls": {
"Changelog": "https://github.com/FullStackWithLawrence/secure-logger/blob/main/CHANGELOG.md",
"Code of Conduct": "https://github.com/FullStackWithLawrence/secure-logger/blob/main/CODE_OF_CONDUCT.md",
"Documentation": "https://pypi.org/project/secure-logger/",
"Homepage": "https://github.com/FullStackWithLawrence/secure-logger",
"Security": "https://github.com/FullStackWithLawrence/secure-logger/blob/main/SECURITY.md",
"Source": "https://github.com/FullStackWithLawrence/secure-logger",
"Tracker": "https://github.com/FullStackWithLawrence/secure-logger/issues"
},
"split_keywords": [
"logging",
"security",
"redaction"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "d79f53d2d3ad9e8b345c5fc47dac3e08c65183af1693c9e0a9e2ed243e83ecac",
"md5": "6bd2aad0c490558673f7d4944947632f",
"sha256": "a56e26b20d26c01e200ce20d7a08d23f6cbfca0deb2f8e84fafd6b00354c9d84"
},
"downloads": -1,
"filename": "secure_logger-0.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "6bd2aad0c490558673f7d4944947632f",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 24790,
"upload_time": "2023-12-09T16:02:44",
"upload_time_iso_8601": "2023-12-09T16:02:44.969103Z",
"url": "https://files.pythonhosted.org/packages/d7/9f/53d2d3ad9e8b345c5fc47dac3e08c65183af1693c9e0a9e2ed243e83ecac/secure_logger-0.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "460a37c7d4b1cd97f3773ab36c29f2688f638de828cf88ee66136a480e6daefa",
"md5": "d8329c7a345494d72ac068ce256c234c",
"sha256": "7a166bf8db6e82b78b1ce1e279cf9e0f5f93abd5b197f8ebf0f156e7ced74614"
},
"downloads": -1,
"filename": "secure-logger-0.2.0.tar.gz",
"has_sig": false,
"md5_digest": "d8329c7a345494d72ac068ce256c234c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 23655,
"upload_time": "2023-12-09T16:02:46",
"upload_time_iso_8601": "2023-12-09T16:02:46.810853Z",
"url": "https://files.pythonhosted.org/packages/46/0a/37c7d4b1cd97f3773ab36c29f2688f638de828cf88ee66136a480e6daefa/secure-logger-0.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-09 16:02:46",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "FullStackWithLawrence",
"github_project": "secure-logger",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "secure-logger"
}