{ "info": { "author": "Luke Arno", "author_email": "luke.arno@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Topic :: Software Development :: Libraries", "Topic :: Utilities" ], "description": "# Runlog\n\nManagable detaied per-run logs for recurring jobs.\n\n\"Why did X happen the last time the Foo job ran for user Bar?\"\n\n\"Job Y blew up when it ran yesterday. Where and why did it fail?\"\n\nRunlog provides a Python standard library logging-based, Redis-backed\nway to store and access logs for the last N interesting runs of a job.\nIt's very simple to add detailed logging to code that runs inside\nyour recurring jobs without cluttering up your normal log files with\nnoisy, interleaving output.\n\nIt is very easy to add this logging to your code. An unambitious,\nCLI allows you to list jobs, list previous and ongoing runs and to output\ntheir logs. (Pipe them to your favorite unix utilities and enjoy.)\n\n## Logging a Job\n\nJob logging is done with normal log calls and a job-logging context\nmanager.\n\n```python\nimport logging\nfrom runlog import RunLogger\n\nrl = RunLogger(redis_config={'host': 'localhost'},\n max_logs=10)\n\nrl.debug(\"You will never see this.\")\n\nwith rl.runlog('recurring-job-32') as logger:\n logger.setLevel(logging.DEBUG)\n rl.debug(\"You will see this in the log of a run of this job.\")\n\nrl.error(\"You don't see this either.\")\n```\n\nCaveat: you will actually see all log messages if you add handlers\nto the root logger. But if that is the case you are drinking from\nthe firehose and it's probably what you want to happen anyway.\n\n## Finding The Output\n\nAssuming you have a `.runlog.conf` that looks like this\n\n```ini\n[runlog]\nmax-logs: 10\n\n[runlog-redis]\nhost: localhost\n```\n\n... you can find the logs for your job like this:\n\n```bash\n$ runlog list-jobs\nrecurring-job-32\n\n$ runlog list-runs recurring-job-32\nrecurring-job-32 2014-04-16-04:35:23.562999\nrecurring-job-32 2014-04-15-04:33:11.463847\n...\n\n$ runlog logs recurring-job-32 2014-04-15-04:33:11.463847 2014-04-16-04:35:23.562999 \n[ ... LOGS OF THE TWO RUNS SPECIFIED ... ]\n```\n\nComing soon: range queries over log messages.\n\n## Handling Errors\n\nIf something blows up inside the job-loggging context manager,\nthe traceback will be added to the log for the current run and\nthe exception will be re-raise. Errors will not be swallowed.\n\n## Throwing Away Boring Logs\n\nIf your job turns out of be a no-op or is in some other way boring\nto you, you can raise a `CancelLog` and just forget the whole thing.\n\n```\nwith rl.runlog('job-127') as logger:\n things_processed = run_job(127)\n if things_processed == []:\n raise CancelLog() # This run is forgotten.\n```\n\nCancelLog will be swallowed, but only _inside_ the context manager.\n\n## Managing Data\n\nSet up a dedicated Redis instance. Cap the memory. Throw away logs\nthat are not interesting. Look at data growth and adjust `max_logs`\nor be more picky about which jobs you log. Archive really interesting\nthings and/or some random samples into some kind of cold storage.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/lukearno/runlog", "keywords": null, "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "runlog", "package_url": "https://pypi.org/project/runlog/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/runlog/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://github.com/lukearno/runlog" }, "release_url": "https://pypi.org/project/runlog/0.1.1/", "requires_dist": null, "requires_python": null, "summary": "Managable detaied per-run logs for recurring jobs.", "version": "0.1.1" }, "last_serial": 1479675, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "71e4eb4af065466b3fc242f5bece7f0e", "sha256": "71f7738ea1457037c2cd9038ed481e3f3fa9d88cb041727c00ab0c9c8382cb7f" }, "downloads": -1, "filename": "runlog-0.1.0.tar.gz", "has_sig": false, "md5_digest": "71e4eb4af065466b3fc242f5bece7f0e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5112, "upload_time": "2014-04-17T03:35:40", "url": "https://files.pythonhosted.org/packages/c2/7d/696beea3b6a6c536d4acf5bbfe998caa9d07d315a2a665a1641e1be5fdcc/runlog-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "5fd2132a6b88a6c8cdecaf5eeb448f37", "sha256": "6b53d160cc52c00f27a32552daf65406bb46ff492a8c1f4dd8cd62fdadb56dda" }, "downloads": -1, "filename": "runlog-0.1.1.tar.gz", "has_sig": false, "md5_digest": "5fd2132a6b88a6c8cdecaf5eeb448f37", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5066, "upload_time": "2015-03-27T04:13:02", "url": "https://files.pythonhosted.org/packages/bf/34/2fb61eac40179280c60c7a9d1d9055e961fe0b3b596394afe18b59f9d8dd/runlog-0.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "5fd2132a6b88a6c8cdecaf5eeb448f37", "sha256": "6b53d160cc52c00f27a32552daf65406bb46ff492a8c1f4dd8cd62fdadb56dda" }, "downloads": -1, "filename": "runlog-0.1.1.tar.gz", "has_sig": false, "md5_digest": "5fd2132a6b88a6c8cdecaf5eeb448f37", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5066, "upload_time": "2015-03-27T04:13:02", "url": "https://files.pythonhosted.org/packages/bf/34/2fb61eac40179280c60c7a9d1d9055e961fe0b3b596394afe18b59f9d8dd/runlog-0.1.1.tar.gz" } ] }