{ "info": { "author": "Niranjan Singh", "author_email": "niranjan32331@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "# Logging #\n***\n> Logging is done to remember what your code does in case you forget it someday! \nApart from finding bugs/ understanding behaviour/ documentation and better visualization.\n\n> ~ Sarvadim (Chapter 0, Verse 010) \n\n\n# django_logger #\n***\n\ndjango_logger is a Python logging library with super powers. It leverages python \n[logging](https://docs.python.org/2/library/logging.html) to log anything and formats it as configured in django settings, \nwhich can be parsed via elastic search and visualized in kibana.\n\nThe default implementation uses `StreamHandler()` and sends all messages to `stdout`. Currently support for Django>=1.9.\n\nWith django_logger, you can:\n\n* Setup your own logger format to log all logs in a specific format.\n* Log a functions input/ output using just a decorator `@FunctionLogger()`.\n* Specify in settings or in decorator, paramater values you wish to hide in logs `@FunctionLogger(secure_args=['password'])`. \n* Mail logger can be set up to send log mails to `ADMINS` configured in django settings file \nappart from logging to `stdout`.\n* Set params in log format in settings which will always be logged in every log and \nset their values globally only once when they change .\n* and much more...\n\n## Change Log ##\n***\n\n### 0.1.0\n * Function logger exit log was breaking for response of object type - FIXED\n * Removed dependency on cRequestMiddleware library to keep global logs, \n Now global log variables can be set anywhere. \n * All global log variables can be set at once by passing as {key:value}.\n * Added support for Django 1.8\n * Solved a minor issue of uploading to pyPi repo.\n * Support for Django 1.9\n * Added support for python 2.7\n\n## Installation ##\n***\n\n pip install django-logger\n\n## Quick start ##\n***\n\n1. Add `DJANGO_LOGGER` in django settings file.\n\n DJANGO_LOGGER = {\n \"APP_NAME\": \"YOUR_APP_NAME\",\n \"LOGGER_NAME\": \"YOUR_LOGGER_NAME\",\n \"MAIL_LOGGER_NAME\": \"YOUR_MAIL_LOGGER_NAME\",\n \"NAMESPACE_KEY\": \"YOUR_APP_NAME_DATA\", # optional, default: _DATA\n \"SECURE_PARAMS\": ('any_secure_param',), # optional, default: ()\n \"LOGGING_FORMAT\": {} # optional, default: {}\n }\n\n2. Add these two lines in the end of `settings` file.\n\n import django_logger\n\n LOGGING = django_logger.LOGGING_FORMAT\n\n3. Test - open shell `python manage.py shell`\n\n import logging\n logger = logging.getLogger('YOUR_LOGGER_NAME')\n mail_logger = logging.getLogger('YOUR_MAIL_LOGGER_NAME')\n\n logger.info('It worked..') # should print log in screen \n mail_logger.info('It's working..') # print log and ADMINS defined in settings should get a mail too \n # provided proper mail settings are in django\n\n4. Happy logging. Dive deeper for better understanding.\n\n\n## Configuration ##\n***\n\nLets see each 'key' from our `DJANGO_LOGGER` configuration below one by one:\n\n DJANGO_LOGGER = {\n \"APP_NAME\": \"APP_EX\",\n \"LOGGER_NAME\": \"LOGGER_EX\",\n \"MAIL_LOGGER_NAME\": \"MAIL_LOGGER_EX\",\n \"NAMESPACE_KEY\": \"APP_DATA_EX\",\n \"SECURE_PARAMS\": ('password_ex',),\n \"LOGGING_FORMAT\": {\n # TWO DIFFERENT KEYS WITH SAME NAME BUT DIFFERENT CASE CAN ALSO BE SET\n # AVOID DOING THAT FOR CONSISTENCY BUT YES YOU HAVE FREEDOM TO DO THAT\n # FOR EX. `C` IN BELOW FORMAT\n\n \"INT_KEY\": int,\n \"FLOAT_KEY\": float,\n \"C\": str,\n \"f\": {\n 'a': str,\n 'b': int,\n 'c': {\n 'c': {}, # for storing dict, if you will give `dict`\n # it will be assumed as \n 'd': dict, # will be assumed as \n }\n },\n\n }\n }\n\nNow lets print this log:\n\n import logging\n logger = logging.getLogger('LOGGER_EX')\n logger.info(\"Just an example.\")\n\nAnd this will be printed on console as: \n\n {\"FUNCTION\":\"\",\"TRACE\":\"\",\"LEVEL\":\"INFO\",\"APP\":\"APP_EX\",\"TIME\":\"2018-03-09T17:06:45.975+05:30\",\"PATH\":\"\",\"LOGGER\":\"LOGGER_EX\",\"LINE\":1,\"APP_DATA_EX\":{\"C\":\"\",\"FLOAT_KEY\":\"0.00\",\"INT_KEY\":\"0\",\"MESSAGE\":{\"TEXT\": \"Just an example.\"},\"f\":{\"a\":\"\",\"c\":{\"c\":\"{}\",\"d\":\"\"},\"b\":0}}}\n\n- APP_NAME : Name of your application which will be used in logs - `APP_EX`\n- LOGGER_NAME : Name of logger which we have used to get this logger config - `LOGGER_EX`\n- MAIL_LOGGER_NAME : Name of mail logger.\n- NAMESPACE_KEY : Key name to be used to throw all logs data. - `APP_DATA_EX`\n- SECURE_PARAMS : This is used while using function decorator to log input output \n of a function and so to just hide (log '***\" instead of actual value) the params given here in tuple. see [example]\n- LOGGING_FORMAT : This defines the actual log format in which its going to be logged, in key for ex. `APP_DATA_EX`\n\n##### LOGGING_FORMAT #####\n***\n\nThis needs to be a dict, and should contain keys which you want in all logs (format : type) \nLet's consider a use case - \n\n\nYou have an application service which takes a person's details, verifies it and sends it to another service to book a loan\nand throws error if any validation fails. \n\nNow in your validation service you have many validator functions (Name, Aadhar, Cibil,\nDOB, etc. ). You would want to log some unique detail of person in every log in order to filter logs based on request or if a \nvalidation fails then to find which validator failed. \n\nYou can do this either logging 'pan_number' everytime and passing it in every function\nor configure this in `DJANGO_LOGGER` settings in `LOGGING_FORMAT` as: \n\n DJANGO_LOGGER = {\n \"APP_NAME\": \"APP_EX\",\n \"LOGGER_NAME\": \"LOGGER_EX\",\n \"MAIL_LOGGER_NAME\": \"MAIL_LOGGER_EX\",\n \"NAMESPACE_KEY\": \"APP_DATA_EX\",\n \"SECURE_PARAMS\": ('password_ex',),\n \"LOGGING_FORMAT\": {\n \"PAN\": \n }\n }\n\nNow everytime to log anything you will have a key `PAN` with default to \"\" as this is a string.\n\n logger = logging.getLogger('LOGGER_EX')\n logger.info(\"Validating aadhar..\")\n\nit logs, check key `APP_DATA_EX`\n\n {\"FUNCTION\":\"\",\"TRACE\":\"\",\"LEVEL\":\"INFO\",\"APP\":\"APP_EX\",\"TIME\":\"2018-03-09T18:43:47.235+05:30\",\"PATH\":\"\",\"LOGGER\":\"LOGGER_EX\",\"LINE\":1,\"APP_DATA_EX\":{\"MESSAGE\":{\"TEXT\": \"Validating aadhar..\"},\"PAN\":\"\"}}\n\n**Note**: float, int, dict (to be given as {}) types will have default values as 0.0, 0 and {} respectively.\n\nNow to set this `PAN` globally when it arrives so that by default whenever there is a log statement it will pick\nup value of `PAN` which has been set globally. It can be set as:\n\n import django_logger\n django_logger.set_global_logs({'PAN':'default_pan'})\n\n**Note**: While setting this global logs as these are stored under a current thread key, make sure to clean global log\nbefore and after exit point of a request/ process as:\n\n import django_logger\n django_logger.clean_global_log()\n\n django_logger.set_global_logs({'PAN':'TYUPS7658K'})\n\n django_logger.clean_global_log()\n\nSo what it does is clean global log so that it doesn't pick up global log variables from previous process just to be safe.\nIt also helps in keeping global log clean. In case your entry points are celery tasks then you can write a pre and post\ncelery signals which cleans global log before and after executing any task. For ex:\n\n import django_logger\n from celery.signals import task_prerun, task_postrun\n\n @task_prerun.connect()\n def task_clean__global_log():\n django_logger.clean_global_log()\n\n @task_postrun.connect()\n def task_clean__global_log():\n django_logger.clean_global_log()\n\n\nNow when you will log anything, after this has been set it will always log PAN.\n\n logger = logging.getLogger('LOGGER_EX')\n logger.info(\"Validating aadhar..\")\n\nit logs, check key `APP_DATA_EX`\n\n {\"FUNCTION\":\"\",\"TRACE\":\"\",\"LEVEL\":\"INFO\",\"APP\":\"APP_EX\",\"TIME\":\"2018-03-09T18:43:47.235+05:30\",\"PATH\":\"\",\"LOGGER\":\"LOGGER_EX\",\"LINE\":1,\"APP_DATA_EX\":{\"MESSAGE\":{\"TEXT\": \"Validating aadhar..\"},\"PAN\":\"default_pan\"}}\n\nSimmilarly, there can be complex configurations set in `LOGGER_FORMAT` to log complex data. Normal text logs goes in `APP_DATA_EX['MESSAGE']['TEXT']` key.\n\n\n##### Decorator #####\n***\n\nIt is often the case when we want to know the behaviour of our code \nwhen it entered any function the parameters passed and what it returned.\nTo do exactly this just put decorator `@FunctionLogger()` above function.\n\n**Note**: Put this decorator in the end among other decorators, for ex.\n\n @staticmethod\n @FunctionLogger()\n def some_static_method():\n # do some boring stuff\n pass\n\nNow, you may not want to log values of some parameters such as password, username, api_key, third_party_key, oauth_key etc.\nTo do this either set parameter name in settings under `SECURE_PARAMS` in a tuple or \npass parameter name in decorator as `@FunctionLogger(secure_args=['password'])` and that parameter value will be logged as \"****\"\n\nfor example:\n\n # configuration\n DJANGO_LOGGER = {\n \"APP_NAME\": \"APP_EX\",\n \"LOGGER_NAME\": \"LOGGER_EX\",\n \"MAIL_LOGGER_NAME\": \"MAIL_LOGGER_EX\",\n \"NAMESPACE_KEY\": \"APP_DATA_EX\",\n \"SECURE_PARAMS\": ('password_ex',),\n \"LOGGING_FORMAT\": {}\n }\n\n # sample function \n from django_logger import FunctionLogger\n\n @FunctionLogger(secure_args=['username'])\n def func_args(text, username, password_ex): # name of parameter should be exactly same as in configuration\n return text + \" Username - \" + password_ex\n\n # call this function\n func_args(\"Hello\",'testing','test123')\n\n # this will log\n {\"FUNCTION\":\"func_args\",\"TRACE\":\"\",\"LEVEL\":\"INFO\",\"APP\":\"APP_EX\",\"TIME\":\"2018-03-12T12:26:38.122+05:30\",\"PATH\":\"\",\"LOGGER\":\"LOGGER_EX\",\"LINE\":1,\"APP_DATA_EX\":{\"MESSAGE\":{\"TEXT\": \"Entering func_args\", \"ARGS\": \"NamedArgs(text='Hello', username='*******', password_ex='*******')\", \"KWARGS\": \"\"}}}\n {\"FUNCTION\":\"func_args\",\"TRACE\":\"\",\"LEVEL\":\"INFO\",\"APP\":\"APP_EX\",\"TIME\":\"2018-03-12T12:26:38.122+05:30\",\"PATH\":\"\",\"LOGGER\":\"LOGGER_EX\",\"LINE\":1,\"APP_DATA_EX\":{\"MESSAGE\":{\"TEXT\": \"Exiting func_args\", \"ARGS\": \"Hello Username - test123\", \"KWARGS\": \"\"}}}\n\n\n # Outputs\n 'Hello Username - test123'\n\nAs you can see in logs, it logged `username` and `password` as \"*****\" but not `text`.\n\n\n### Examples: ###\n***\n\nConfiguration:\n\n # put this in django settings file\n DJANGO_LOGGER = {\n \"APP_NAME\": \"APP_EX\",\n \"LOGGER_NAME\": \"LOGGER_EX\",\n \"MAIL_LOGGER_NAME\": \"MAIL_LOGGER_EX\",\n \"NAMESPACE_KEY\": \"APP_DATA_EX\",\n \"SECURE_PARAMS\": ('password_ex',),\n \"LOGGING_FORMAT\": {\n # TWO DIFFERENT KEYS WITH SAME NAME BUT DIFFERENT CASE CAN ALSO BE SET\n # AVOID DOING THAT FOR CONSISTENCY BUT YES YOU HAVE FREEDOM TO DO THAT\n # FOR EX. `C` IN BELOW FORMAT\n\n \"INT_KEY\": int,\n \"FLOAT_KEY\": float,\n \"C\": str,\n \"f\": {\n 'a': str,\n 'b': int,\n 'c': {\n 'c': {}, # for storing dict, if you will give `dict`\n # it will be assumed as \n 'd': dict, # will be assumed as \n }\n },\n\n }\n }\n\n import django_logger\n LOGGING = django_logger.LOGGING_FORMAT\n\nExecuting all this in `python manage.py shell` :\n\n import logging\n logger = logging.getLogger('LOGGER_EX')\n\n\n1. Log simple warning:\n\n logger.warning(\"Validation failed for loan {} .\".format('loan_id'))\n {\"FUNCTION\":\"\",\"TRACE\":\"\",\"LEVEL\":\"WARNING\",\"APP\":\"APP_EX\",\"TIME\":\"2018-03-12T12:49:18.205+05:30\",\"PATH\":\"\",\"LOGGER\":\"LOGGER_EX\",\"LINE\":1,\"APP_DATA_EX\":{\"C\":\"\",\"FLOAT_KEY\":\"0.00\",\"INT_KEY\":\"0\",\"MESSAGE\":{\"TEXT\": \"Validation failed for loan loan_id .\"},\"f\":{\"a\":\"\",\"c\":{\"c\":\"{}\",\"d\":\"\"},\"b\":0}}}\n\n2. Log with some arguments:\n\n **Note**: key `MESSAGE` AND `KWARGS` must be there else they will not be logged.\n\n logger.info({\n \"MESSAGE\": \"API request invoked by client {}.\".format(\"some client\"),\n\n # It's better to give same key names inside `kwargs` in all logs, as they can be used later to visualize too for ex. api request data as `DATA` and response as `RESPONSE`.\n # so all api logs will have same signature in `kwargs`\n \"KWARGS\": {\n \"CLIENT_ID\": \"123\",\n \"DATA\": {\"name\":\"abc\",\"loan_id\":\"1234\"} # it can be request.data but if that is too much data then try to put only required information\n }\n })\n\n\n {\"FUNCTION\":\"\",\"TRACE\":\"\",\"LEVEL\":\"INFO\",\"APP\":\"APP_EX\",\"TIME\":\"2018-03-12T12:56:18.489+05:30\",\"PATH\":\"\",\"LOGGER\":\"LOGGER_EX\",\"LINE\":5,\"APP_DATA_EX\":{\"C\":\"\",\"FLOAT_KEY\":\"0.00\",\"INT_KEY\":\"0\",\"MESSAGE\":{\"TEXT\": \"API request invoked by client some client.\", \"ARGS\": \"\", \"KWARGS\": \"{'DATA': {'loan_id': '1234', 'name': 'abc'}, 'CLIENT_ID': '123'}\"},\"f\":{\"a\":\"\",\"c\":{\"c\":\"{}\",\"d\":\"\"},\"b\":0}}}\n\n3. Log entry-exit for a function having args and kwargs.\n\n from django_logger import FunctionLogger\n @FunctionLogger()\n def my_func(a,b=2,c=0,d=\"hello\"):\n return a,b,c,d\n\n print my_func(1,2,c=3,d=\"Namaste\")\n\n **Note**: As argument `b` was not passed as kwargs so it will be treated as args only.\n\n {\"FUNCTION\":\"my_func\",\"TRACE\":\"\",\"LEVEL\":\"INFO\",\"APP\":\"APP_EX\",\"TIME\":\"2018-03-12T13:05:38.638+05:30\",\"PATH\":\"\",\"LOGGER\":\"LOGGER_EX\",\"LINE\":2,\"APP_DATA_EX\":{\"C\":\"\",\"FLOAT_KEY\":\"0.00\",\"INT_KEY\":\"0\",\"MESSAGE\":{\"TEXT\": \"Entering my_func\", \"ARGS\": \"NamedArgs(a=1, b=2)\", \"KWARGS\": \"{'c': 3, 'd': 'Namaste'}\"},\"f\":{\"a\":\"\",\"c\":{\"c\":\"{}\",\"d\":\"\"},\"b\":0}}}\n {\"FUNCTION\":\"my_func\",\"TRACE\":\"\",\"LEVEL\":\"INFO\",\"APP\":\"APP_EX\",\"TIME\":\"2018-03-12T13:05:38.638+05:30\",\"PATH\":\"\",\"LOGGER\":\"LOGGER_EX\",\"LINE\":2,\"APP_DATA_EX\":{\"C\":\"\",\"FLOAT_KEY\":\"0.00\",\"INT_KEY\":\"0\",\"MESSAGE\":{\"TEXT\": \"Exiting my_func\", \"ARGS\": \"(1, 2, 3, 'Namaste')\", \"KWARGS\": \"\"},\"f\":{\"a\":\"\",\"c\":{\"c\":\"{}\",\"d\":\"\"},\"b\":0}}}\n\n # output\n (1, 2, 3, 'Namaste')\n\n### Contribution guidelines ###\n***\n\n* Writing tests - Always welcome to improve on this, at this time its greater than 90%.\n\n* Other guidelines - Feel free to suggest any more feature or raise a pull request.\n\n### Who do I talk to? \n***\n\n* Author - Niranjan Singh\n\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/NiranjanSingh/django-logger", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "easy-django-logger", "package_url": "https://pypi.org/project/easy-django-logger/", "platform": "", "project_url": "https://pypi.org/project/easy-django-logger/", "project_urls": { "Homepage": "https://github.com/NiranjanSingh/django-logger" }, "release_url": "https://pypi.org/project/easy-django-logger/0.1.1/", "requires_dist": [ "Django (<2,>=1.8)", "arrow (>=0.12.1)", "pytz (>=2017.3)" ], "requires_python": "", "summary": "Django logger to log formatted logs parsable via elastic search and visualize via kibana.", "version": "0.1.1" }, "last_serial": 5119483, "releases": { "0.1.1": [ { "comment_text": "", "digests": { "md5": "de42e69373cde78c7433988bac5f8ced", "sha256": "0f3d27da4eea84df2369496169664c06a449ccfd9b37718385bf3999da1e70e4" }, "downloads": -1, "filename": "easy_django_logger-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "de42e69373cde78c7433988bac5f8ced", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 25344, "upload_time": "2019-04-09T15:51:18", "url": "https://files.pythonhosted.org/packages/bc/43/270a6b7bef3e070da94586064506dfb61bd01a9e43b1c4831841609e6b23/easy_django_logger-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1496d728e4005ff1e8ecfd06f610af92", "sha256": "47982c9e6b8aa55538b1a33af41a4c062cc04f5999d96d174657f010fad0a4b2" }, "downloads": -1, "filename": "easy-django-logger-0.1.1.tar.gz", "has_sig": false, "md5_digest": "1496d728e4005ff1e8ecfd06f610af92", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16618, "upload_time": "2019-04-09T15:51:23", "url": "https://files.pythonhosted.org/packages/90/ce/03ddbc56a30f22595e6f509fc04c55a7cfa324ca7913af8d6454bfc7d562/easy-django-logger-0.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "de42e69373cde78c7433988bac5f8ced", "sha256": "0f3d27da4eea84df2369496169664c06a449ccfd9b37718385bf3999da1e70e4" }, "downloads": -1, "filename": "easy_django_logger-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "de42e69373cde78c7433988bac5f8ced", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 25344, "upload_time": "2019-04-09T15:51:18", "url": "https://files.pythonhosted.org/packages/bc/43/270a6b7bef3e070da94586064506dfb61bd01a9e43b1c4831841609e6b23/easy_django_logger-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1496d728e4005ff1e8ecfd06f610af92", "sha256": "47982c9e6b8aa55538b1a33af41a4c062cc04f5999d96d174657f010fad0a4b2" }, "downloads": -1, "filename": "easy-django-logger-0.1.1.tar.gz", "has_sig": false, "md5_digest": "1496d728e4005ff1e8ecfd06f610af92", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16618, "upload_time": "2019-04-09T15:51:23", "url": "https://files.pythonhosted.org/packages/90/ce/03ddbc56a30f22595e6f509fc04c55a7cfa324ca7913af8d6454bfc7d562/easy-django-logger-0.1.1.tar.gz" } ] }