{ "info": { "author": "Mike Miller", "author_email": "mixmastamyk@github.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries" ], "description": "\nOut\n===========\n\nFun take on logging for non-huge projects\u2014out gets \"outta\" the way!\n\n(Why's are covered in the background_anchor_ section at the bottom.)\n\n\nInstall\n------------\n\n.. code-block:: shell\n\n \u23f5 pip3 install out #\u00a0or out[highlight]\n\n\nFeatures\n------------\n\nFirst of all,\nout is concise as hell,\nbasically a singleton logger configuration ready on import.\nIn interactive mode:\n\n.. code-block:: python\n\n >>>\u00a0import out\n\n >>>\u00a0out('And away we go\u2026') # configurable default level\n \ud83c\udd78 main/func:1 And away we go\u2026\n\n >>>\u00a0out.warn('Danger Will Robinson!')\n \ud83c\udd86 main/func:1 Danger Will Robinson!\n\n(Imagine with nice ANSI colors. \ud83d\ude01)\nOut has simple themes for message formats, styles, and icons.\nNot to worry,\nout is more conservative in \"production mode,\"\nwhich may be turned on automatically by redirecting ``stderr``:\n\n.. code-block:: shell\n\n \u23f5 python3 script.py |& cat #\u00a0bash, for fish use: ^|\n 2018-09-10 17:18:19.123 \u2717 ERROR main/func:1 Kerblooey!\n\n\n.. note::\n\n This is a library to simplify logging configuration for *applications.*\n\n Libraries and independent modules should continue on logging *messages* as\n they always have:\n\n .. code-block:: python\n\n import logging\n\n log = logging.getLogger(__name__)\n\n # do not configure loggers, just use:\n log.debug('foo')\n\n\nColors, Highlighting, Unicode Icons\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n- Colors are ready to go in interactive mode,\n and turn off automatically when output is redirected.\n\n- Unicode symbols are used throughout as \"icons\" for increased readability and\n conciseness.\n\n- Syntax highlighting of data structures (oft parsed from remote APIs) is\n available too, via Pygments.\n\n\nUseful defaults, and easy to configure!\n\n.. code-block:: python\n\n >>>\u00a0out.configure(\n level='note', # level messages passed: str/int\n default_level='info', # when called w/o a method: out('\u2026')\n datefmt='\u2026', # see strftime\n msgfmt='\u2026', # see logging and below\n stream=file, # stderr is default\n\n theme=name|dict, # see below\n icons=name|dict, # about themes\n style=name|dict,\n lexer='python3', # optional highlighting\n )\n\nWe'll go into more detail below.\n\n\nLog Message Format\n~~~~~~~~~~~~~~~~~~~\n\nBy default out supports the curly-brace ``{}`` formatting style for both the\nlog message format and message template,\nas it is a bit easier to read than printf-style.\nField definitions are found in the Python\n`logging docs `_::\n\n {asctime} Textual time when the LogRecord created.\n {msecs} Millisecond portion of the creation time\n {filename} Filename portion of pathname\n {funcName} Function name\n {lineno) Source line number where called.\n {levelno} Numeric logging level for the message\n {levelname} Text logging level for the message\n {pathname} Full path of the source file called.\n {message} The result of record.getMessage().\n {module} Module (name portion of filename)\n {name} Name of the logger (logging channel)\n\nUse of the\n``out.format.ColorFormatter`` class adds these additional fields::\n\n {on}{icon}{off} Per-level style and icon support.\n\nFor example:\n\n.. code-block:: python\n\n out.configure(\n msgfmt='{on}{icon}{levelname:<7}{off} {message}',\n )\n\n\nDateTime Format\n++++++++++++++++++\n\nThese are configuable via the standard\n`strftime `_\nsyntax and the\n``datefmt`` keyword to ``configure``.\n\n.. code-block:: python\n\n out.configure(\n datefmt='%y-%m-%d %H:%M:%S',\n )\n\n\nMessage:\n++++++++++++++++++\n\nWhen writing messages, printf ``%`` formatting style is supported as well\ndue to compatibility requirements with a majority of libraries:\n\n.. code-block:: python\n\n out.warn('foo: %s', bar)\n out.warn('foo: {}', bar)\n\nThe second form may be used also,\nthough it will be a tiny bit slower,\nsince the printf-style must be tried first.\n\nYou'll want to use one of these forms,\nas (in logging) they skip formatting of the string when the message isn't\nsent.\n\n\nLevels++\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWhile the\n`standard levels `_\ncontinue to exist\n(``NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL``).\nA few additions and slight modifications have been made.\nCommonly requested:\n\n- ``TRACE``, for absurdly voluminous data, perhaps system calls or network\n traffic.\n\n- ``NOTE``, for **positive** messages\n that should/must be shown by default---\\\n unlike the standard warning,\n which could encourage the viewer to worry. e.g.:\n\n | ``NOTE`` - Token is ABCXYZ, rather than\u2026\n | ``WARNING`` - Token is ABCXYZ.\n\n- ``EXCEPT``, to differentiate common from unexpected errors.\n Think ``FileNotFound`` vs. ``Exception``.\n\n- ``FATAL``, an alias of ``CRITICAL``,\n since that name is long, pushes alignment,\n and does not capture intent as well as fatal.\n Std-lib already allows this but still labels it critical on output.\n Out does not.\n\n\nThemes\n~~~~~~~~~~~~~~~~~~\n\n\nIcons and Styles\n+++++++++++++++++\n\n``out`` can be themed with icon sets and/or styles and are simply dictionaries\nwith one entry per level.\n\n\n.. code-block:: python\n\n >>> from out.themes import themes, icons, styles\n\n >>> icons['circled'] # Unicode\n {'TRACE': '\ud83c\udd63', 'DEBUG': '\ud83c\udd53', 'INFO': '\ud83c\udd58', 'WARNING': '\ud83c\udd66',\n 'NOTE': '\ud83c\udd5d', 'ERROR': '\ud83c\udd54', 'EXCEPT': '\ud83c\udd67', 'CRITICAL': '\ud83c\udd55',\n 'FATAL': '\ud83c\udd55', 'NOTSET': '\ud83c\udd5d'}\n\n >>> styles['blink'] # ANSI escapes\n {'TRACE': '\\x1b[35m', 'DEBUG': '\\x1b[34m', 'INFO': '\\x1b[32m',\n 'WARNING': '\\x1b[93m', 'NOTE': '\\x1b[96m', 'ERROR': '\\x1b[31m',\n 'EXCEPT': '\\x1b[91m', 'CRITICAL': '\\x1b[97m',\n 'FATAL': '\\x1b[97;5m', 'NOTSET': '\\x1b[0m'}\n\nThe\n`console `_\npackage is a good choice to generate ANSI styles for the levels,\nas well as styling other fields:\n\n.. code-block:: python\n\n from console import fg, bg, fx\n import out\n\n blue_note = dict(\n NOTE=str(fg.lightblue + fx.bold + fx.reverse),\n # other levels\u2026\n )\n out.configure(\n style=blue_note, # \u2190 level styles, \u2193 field styles\n msgfmt=bg.blue('{asctime}') + ' {message}',\n )\n out.note('John Coltrane')\n\n\nCreating and Using Themes\n++++++++++++++++++++++++++\n\nA full theme is the whole kit together in a mapping\u2014\\\nstyles, icons, ``message`` and/or ``datefmt`` templates:\n\n.. code-block:: python\n\n >>> interactive_theme = {\n 'style': {}, # level:value mapping, see above\n 'icons': {}, # level:value\n 'fmt': '{asctime} {icon} {message}', #\u00a0message format\n 'datefmt': '%H:%M:%S', #\u00a0date/time format,\n }\n\n\nIn the ``configure`` method of the out logger,\nto use a theme from the themes module,\nsimply specify an existing one by name:\n\n.. code-block:: python\n\n >>>\u00a0out.configure(\n theme='production',\n )\n\nOr by setting a custom mapping, as created above:\n\n.. code-block:: python\n\n >>>\u00a0out.configure(\n theme=interactive_theme, # or perhaps just icons:\n icons=dict(DEBUG='\u2022 ', INFO='\u2713 ', WARNING='\u26a0 ', ) #\u00a0\u2026\n )\n\nA few themes are bundled:\n\nIcons:\n ascii,\n ascii_symbol,\n circled,\n circled_lower,\n rounded,\n symbol\n\nStyles:\n - norm\n - bold\n - mono (monochrome)\n - blink (fatal error only)\n\nFull themes:\n - interactive\n - production\n - plain (Uses logging.Formatter for lower overhead.)\n - json (Uses formatter.JSONFormatter)\n - mono (monochrome)\n - linux_interactive, linux_production (vga console)\n\n\n.. note::\n\n When there are conflicting arguments to the ``configure`` method,\n the last specified will win.\n This requires a Python version >=3.6, due to ordered keyword args.\n Below this version it is not recommended to try since keyword order\n will be undefined and therefore the result.\n One workaround, call ``configure()`` twice.\n\n\nSyntax Highlighting w/Pygments\n--------------------------------\n\nWhen Pygments is installed,\nsyntax highlighting is available for Python data structures and code,\nas well as JSON and XML strings\u2014\\\npotentially anything Pygments can highlight.\nThis can be helpful when debugging remote APIs for example.\n\nA lexer may be\n`selected by name `_\nvia ``configure(lexer=LEXER_NAME)``,\ndisabled by setting to ``None``.\nSome common lexer names are: ``('json', 'python3', 'xml')``.\n\n**Use:**\n\nMessage text following a ``{, [, <, or '`` char\nis highlighted with the current\nlexer+formatter:\n\n.. code-block:: python\n\n out.configure(level='trace')\n\n # default Python3\n out.trace('PYON data: %s',\n {'data': [None, True, False, 123]})\n\n out.configure(lexer='json')\n out.trace('JSON data: '\n '{\"data\": [null, true, false, 123]}')\n\n(Imagine with lovely ANSI flavors. \ud83d\ude01)\n\n\nTips\n---------\n\n- By default the logger prints to ``stderr``.\n The reason being that when used in an interactive script normal application\n output may be easily segregated from log messages during redirection.\n\n .. code-block:: shell\n\n # bash, fish\n \u23f5 script.py 2> logfile.txt\n\n Configurable via the ``stream`` keyword to ``.configure()``:\n\n .. code-block:: python\n\n import sys, out\n\n out.configure(\n stream=sys.stdout,\n )\n\n- Upgrading a long script from ``print()`` is easy:\n\n .. code-block:: python\n\n import out\n\n print = out # or other level: out.note\n\n Or perhaps some logging was already added, but you'd like to downsize.\n Add this to your main script::\n\n import out as logger\n\n Less code will need to be changed.\n\n.. ~ - Want to keep your complex configuration but use the ``ColorFormatter`` class\n .. ~ and themes in your own project?\n\n- The ``ColorFormatter`` and ``JSONFormatter`` classes can be used in your own\n project:\n\n .. code-block:: python\n\n >>> from out.format import ColorFormatter\n\n >>> cf = ColorFormatter()\n >>> handler.setFormatter(cf)\n\n- To print the current logging configuration:\n\n .. code-block:: python\n\n >>> out.log_config() # quotes to shut off highlighting:\n '''\n \ud83c\udd73 Logging config:\n \ud83c\udd73 / name: main, id: 139973461370360\n \ud83c\udd73 .level: trace (7)\n \ud83c\udd73 .default_level: info (20)\n \ud83c\udd73 + Handler: 0 (NOTSET)>\n \ud83c\udd73 + Formatter: \n \ud83c\udd73 .style: \n \ud83c\udd73 .datefmt: '%H:%M:%S'\n \ud83c\udd73 .msgfmt: ' {on}{icon}{off} {message}'\n '''\n\nThe logger in the main script file is named \"main,\"\nalso known as the \"root\" logger.\n\n\nTroubleshooting\n-----------------\n\n- If you'd like to know what ``out`` is doing,\n try running the ``.log_config()`` method to log what's currently up:\n\n .. code-block:: python\n\n >>> out.log_config()\n\n .. code-block:: shell\n\n \ud83c\udd73 out logging config, version: '0.70a1'\n \ud83c\udd73 .name: main, id: 0x7f88e9ec7198\n \ud83c\udd73 .level: debug (10)\n \ud83c\udd73 .default_level: info (20)\n \ud83c\udd73 + Handler: 0 (NOTSET)>\n \ud83c\udd73 + Formatter: \n \ud83c\udd73 .datefmt: '%H:%M:%S'\n \ud83c\udd73 .msgfmt: ' {on}{icon:<2}{off} \\x1b[38;5;242m{name}/\\x1b[38;5;245m{funcName}:\\x1b[32m{lineno:<3}\\x1b[0m {message}'\n \ud83c\udd73 fmt_style: \n \ud83c\udd73 theme.styles: {'TRACE': '\\x1b[35m', 'DEBUG': '\\x1b[34m', 'INFO': '\\x1b[32m', 'NOTE': '\\x1b[96m', 'WARNING': '\\x1b[93m', 'ERROR': '\\x1b[31m', 'EXCEPT': '\\x1b[91m', 'CRITICAL': '\\x1b[97m', 'FATAL': '\\x1b[97m', 'NOTSET': ''}\n \ud83c\udd73 theme.icons: {'TRACE': '\ud83c\udd83', 'DEBUG': '\ud83c\udd73', 'INFO': '\ud83c\udd78', 'NOTE': '\ud83c\udd7d', 'WARNING': '\ud83c\udd86', 'ERROR': '\ud83c\udd74', 'EXCEPT': '\ud83c\udd87', 'CRITICAL': '\ud83c\udd75', 'FATAL': '\ud83c\udd75', 'NOTSET': '\ud83c\udd7d'}\n \ud83c\udd73 highlighting: 'Python3Lexer', 'Terminal256Formatter'\n\n Import ``out`` in debug mode first and you can see any logging other modules do\n as the start up.\n\n- If you're using fbterm, make sure the ``TERM`` environment variable is set\n to ``fbterm``.\n This makes several adjustments to help it work better under that terminal.\n\n\n.. _background_anchor:\n\nBackground\n--------------------------\n\nIf you're here it's very likely you already know that the Python standard\nlogging module is extremely flexible,\nand that's great.\nUnfortunately, it is overkill for small to medium projects,\nand these days many larger ones too.\nAdditionally,\nits various Java-isms grate on the nerves,\naccentuating a big enterprisey design.\n\nMeanwhile,\nthe rise of\n`12 Factor App `_\npatterns for daemons and services\nmeans that simply logging to stdout/err is expected and desired\nfor portability:\n\n *A twelve-factor app never concerns itself with routing or storage of its\n output stream. It should not attempt to write to or manage logfiles.\n Instead, each running process writes its event stream, unbuffered, to\n stdout. During local development, the developer will view this stream in\n the foreground of their terminal to observe the app\u2019s behavior.*\n\n\nTherefore,\nfor many (if not most) applications,\nall the complexity and mumbo-jumbo in the logging package documentation about\nmultiple loggers with different levels, different handlers, formatters,\nadapters, filters, rotation,\nand complex configuration is flexibility at the *wrong level!*\n\u00a0In fairness,\nthis may not have always been the case,\nand can still be helpful, perhaps on Windows.\n\nAdditionally, logging tools have also become standardized over time,\nhandling cross-language and cross-platform messages.\nImagine a pipeline where log events are routed and multiple tools can be\nplugged in or out as needed\u2014\\\norganization-wide rather than app- or language-wide.\n\nSo, unless you have unique requirements,\nthere's no need to reimplement ``logrotate``, ``syslog``, ``systemd``, and\nproprietary metrics tools in every programming language.\nJust blast those logs to stdout/stderr and get logging *outta* the way!\n\nEnter the ``out`` project.\nIt's ready to start logging from the get go.\nIt uses Python's standard logging infrastructure by default,\nso is still quite flexible when need be.\n\nWell, you've heard this before.\nHowever, *out* tries a bit harder create a fun, easy-to-use interface,\nas discussed above.\n\n**Naming**\n\nRegarding the name,\nwell of course would have liked something along the lines of ``log`` but all\nvariations of that are *long gone* on PyPI.\n``out()`` is a name I've often used over the years as a poor-man's logger\u2014\\\nreally a functional wrapper around ``print``,\nuntil I could get around to adding proper logging.\nNow, the tradition continues.\nThe name is short, simple, and conceptually fits,\nif a little bland.\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/mixmastamyk/out", "keywords": "log logging events levels color terminal console standard out err", "license": "LGPL 3", "maintainer": "", "maintainer_email": "", "name": "out", "package_url": "https://pypi.org/project/out/", "platform": "", "project_url": "https://pypi.org/project/out/", "project_urls": { "Homepage": "https://github.com/mixmastamyk/out" }, "release_url": "https://pypi.org/project/out/0.71/", "requires_dist": null, "requires_python": "", "summary": "Fun take on logging for non-huge projects. Gets \"outta\" the way.", "version": "0.71" }, "last_serial": 5908365, "releases": { "0.60": [ { "comment_text": "", "digests": { "md5": "2e2aa98cbf60dc999c2d9765da2fc2ae", "sha256": "57f9b31600f6c9095d79eae9a939a4394a381b9a5d6e32bda5ff0fd0795857a8" }, "downloads": -1, "filename": "out-0.60-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "2e2aa98cbf60dc999c2d9765da2fc2ae", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 18608, "upload_time": "2018-10-19T23:52:33", "url": "https://files.pythonhosted.org/packages/46/3c/a0b706ecf5098d380125b2c3598d1afddb2384271109fbb0533868e466ad/out-0.60-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "eeec920cb8ea75af42dc78a9624ed42c", "sha256": "011596f4224fb4ff6332a774e340ced08002bfdf52b688b88198785bdab545d7" }, "downloads": -1, "filename": "out-0.60.tar.gz", "has_sig": false, "md5_digest": "eeec920cb8ea75af42dc78a9624ed42c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14691, "upload_time": "2018-10-19T23:52:31", "url": "https://files.pythonhosted.org/packages/19/44/c6c53af491a0a02bc455131c79e71d8df7e0c680eeeab848e4839c09048e/out-0.60.tar.gz" } ], "0.71": [ { "comment_text": "", "digests": { "md5": "8aaf1d146798366066e2fa6c3fb00186", "sha256": "866a63ceffce762265a1a36172c6c46b6bc7cbe2b671579f4e403c3b102b4ffa" }, "downloads": -1, "filename": "out-0.71-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8aaf1d146798366066e2fa6c3fb00186", "packagetype": "bdist_wheel", "python_version": "3.7", "requires_python": null, "size": 21166, "upload_time": "2019-09-30T08:23:24", "url": "https://files.pythonhosted.org/packages/f4/ae/8d97a74282020c7ef6f72ba8fb1aab66da6899188770bc7193244fbed889/out-0.71-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e3a1d026d6c118499f2369c6ff2c5a39", "sha256": "aff37f93ce774773790d1b3e0cf9022b3dbe31c1c1efdbca5c71f467799f423f" }, "downloads": -1, "filename": "out-0.71.tar.gz", "has_sig": false, "md5_digest": "e3a1d026d6c118499f2369c6ff2c5a39", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22383, "upload_time": "2019-09-30T08:23:22", "url": "https://files.pythonhosted.org/packages/53/57/56ecad83fce9b64078d600e8b73451c5c89e1ab4b0665af0aa76c1571551/out-0.71.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "8aaf1d146798366066e2fa6c3fb00186", "sha256": "866a63ceffce762265a1a36172c6c46b6bc7cbe2b671579f4e403c3b102b4ffa" }, "downloads": -1, "filename": "out-0.71-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8aaf1d146798366066e2fa6c3fb00186", "packagetype": "bdist_wheel", "python_version": "3.7", "requires_python": null, "size": 21166, "upload_time": "2019-09-30T08:23:24", "url": "https://files.pythonhosted.org/packages/f4/ae/8d97a74282020c7ef6f72ba8fb1aab66da6899188770bc7193244fbed889/out-0.71-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e3a1d026d6c118499f2369c6ff2c5a39", "sha256": "aff37f93ce774773790d1b3e0cf9022b3dbe31c1c1efdbca5c71f467799f423f" }, "downloads": -1, "filename": "out-0.71.tar.gz", "has_sig": false, "md5_digest": "e3a1d026d6c118499f2369c6ff2c5a39", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22383, "upload_time": "2019-09-30T08:23:22", "url": "https://files.pythonhosted.org/packages/53/57/56ecad83fce9b64078d600e8b73451c5c89e1ab4b0665af0aa76c1571551/out-0.71.tar.gz" } ] }