{ "info": { "author": "Johnny Wezel", "author_email": "dev-jay@wezel.name", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Information Technology", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Natural Language :: English", "Operating System :: POSIX", "Operating System :: Unix", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Topic :: System :: Monitoring" ], "description": "Lognotify\n=========\n\nThis is yet another real-time log scanner done for the ever reoccurring reason of failure to find an existing suitable\ntool.\n\nFeatures\n--------\n\n* simple, yet flexible configuration in the `YAML `_ format\n* actions programmable in Python, Tcl or Bash\n* log rotation detection\n* variable leading log context for every event\n* burst mode: collect events within a certain time frame and report them together\n\nConfiguration\n-------------\n\nLognotify reads a configuration file specified on the command line with the ``--config`` or ``-c`` option. The\nconfiguration specifies what content to search for and what to do if some is found in the log.\n\nOverview\n........\n\nConsider this example::\n\n when:\n - error\n - problem\n - critical\n - fatal\n - bad\n -\n - not\n - ^perl\n - ^/pascal/i\n do:\n python: |\n if logfile:\n print(logfile, messages[-1][-1])\n burst: 2\n ---\n when:\n - strange\n do: |\n echo $logfile: ${message[-1]}\n\nA configuration can have one ore more sections, denoted by a ``---`` delimiting line. Each section specifies what to\nlook for and what to do if something interesting is found.\n\nSections\n........\n\nEach section consists of a `when` clause and a `do` clause. For every line from a logfile, all sections are checked for\nmatching search expressions in the `when` clause. When a match is found for a section, the corresponding `do` clause\nis executed.\n\n`When` clause\n.............\n\nThe `when` clause contains an itemized list of expressions to searche for in every incoming line from the log.\nVariations in syntax specify how to search for the item. The expressions are tried in order. As soon as a match is\nfound, the `do` clause is executed and processing of this particular section is terminated.\n\nThe `when` list forms an `OR`-expression. Within the list, sublists may specify `AND`-expressions. Thus ::\n\n - expr1\n -\n - expr2a\n - expr2b\n\nmeans ::\n\n expr1 OR (expr2a AND expr2b)\n\nGroups can be infinitely nested. The general rule is that every group within an `OR` group is an `AND` group and vice\nversa.\n\nSearch expressions\n..................\n\nA search expression can have one of the following forms:\n\n**word**\n Search for `word` irrespective of case and match only at word boundaries. Thus ``error`` matches in the following\n lines:\n\n Error: invalid syntax\n\n An error occurred.\n\n No error-checking enabled.\n\n but *not* in:\n\n No errorchecking.\n\n maxerror\n\n If you want to match irrespective of word boundaries, you have to use regular expressions (see below).\n\n**/word/[flags]**\n Search for a `regular expression `_. Some flags for altering the\n operation are available:\n\n *i*\n match case insensitive. See `IGNORECASE `_.\n\n *m*\n match in multi-line mode. Probably not very useful. See\n `MULTILINE `_.\n\n *l*\n match according to the current locale. See\n `LOCALE `_.\n\n *s*\n make '.' match any character, including newline. See\n `DOTALL `_.\n\n *u*\n match according to the Unicode character properties table. See\n `UNICODE `_.\n\n *x*\n parse verbose regex with comments and white space. See\n `VERBOSE `_.\n\nAll these expressions can be prefixed with a caret (``^``) to mean \"do not match word\":\n\n**^word**\n\n**^/word/**\n\n.. note::\n\n Since the whole configuration is expressed in YAML, strings containing certain characters must be quoted in order\n not to interfere with the YAML syntax. These characters are: ``[ ] { } ! \" ' : ? % @ , - # ~ | > * &``. Also,\n certain words have special meaning in YAML and must therefore also be quoted: ``yes``, ``no``, ``on``, ``off``,\n ``true``, ``false``, and ``null``.\n\nPitfalls\n........\n\nThe search algorithm gives rise to surprises in certain constellations. One common error is to request something\nlike this::\n\n -\n - not\n - ^this\n -\n - not\n - ^that\n\nwhere `^this` and `^that` cancel each other out. If a line contains 'not' it will always match, no matter whether `this`\nor `that` occurs in the line. The proper way would be ::\n\n -\n - not\n - ^this\n - ^that\n\nThe most common pattern is to search for any line containing `word1`, `word2` or `word3` but not `except1` or `except2`.\nYou might be inclined to write this as ::\n\n - word1\n - word2\n - word3\n -\n - ^except1\n - ^except2\n\nBut this would not work. The way to do it goes along the follong lines: written as a logical expression, it would be ::\n\n (word1 OR word2 OR word3) AND (NOT except1 OR NOT except2)\n\nwhich translates to ::\n\n (word1 OR word2 OR word3) AND NOT except1 AND NOT except2\n\nwhich, expressed as list operations, translates to ::\n\n AND(OR(word1, word2, word3), NOT(except1), NOT(except2))\n\nWe have therefore an `AND` list on top. However, in lognotify we start out in an `OR` list. We therefore have to put our\n`AND` list as the single element into the top `OR` list. The final result would be ::\n\n # OR list\n -\n # AND list\n -\n # OR list\n - word1\n - word2\n - word3\n - ^except1\n - ^except2\n\n`Do` clause\n...........\n\nThe `do` clause specifies what action to take when one of the expressions in the `when` clause matches. To run commands\non the selected logfile lines, `Python `_, `bash` or `Tcl `_ can be used. Some\nvariables are injected, depending on the language used. Scripts receive one or more events at a time depending on\nwhether context and/or burst mode was requested. If neither context not burst mode is requested, one single line is\nreported at a time.\n\n.. note::\n\n Use the pipe character at the end of a line prior to the code block to cause YAML to process the following indented\n block without interpretation, leaving line endings intact (see the examples below).\n\nContext\n'''''''\n\nContext is a number of lines running up to the actual log event line. It can be requested with the ``--config``/``-C``\nflag. Context lines are marked with a ``True`` value in `Python` or `Tcl` or a value of 1 in `bash` or `sh` to\ndistinguish them from log lines. However, if a context line is also a regular log line (appearing because it is part of\na burst) it is not marked as such.\n\nBurst mode\n''''''''''\n\nIn burst mode, log lines arriving within a certain time frame are kept together and appear in the same call. Burst mode\ncan be requested either as a `burst` specifier in a `do` clause or with a ``--burst`` or ``--force-burst`` command line\nflag. Good values for burst time frames are between 2 and 5 seconds. The ``--force-burst`` flag overrides values\nspecified in `do` clauses while ``--burst`` does not.\n\nPython\n''''''\n\n`Python` code can be one block or be split into an initialization section and a runtime section. The former is executed\nonce at startup and is intended to contain stuff like ``import`` statements, function definitions and the like. The\nlatter is run for every event.\n\nIn `Python`, the following variables are available:\n\n**logfile**\n A string containing the path of the logfile where the event was coming from\n**messages**\n A list of tuples. For each event the tuple contains:\n - a bool which is True if the entry is a context line\n - the sequence number\n - a float with a timestamp\n - a string with the message text\n\nExample (assuming Python3 syntax)::\n\n do:\n python: |\n for msg in messages:\n print('%s: %s' % (logfile, msg[3]))\n\nExample with initialization (assuming Python3 syntax)::\n\n python:\n - |\n # Setup UDP socket\n import sys\n import socket\n sock = socket.socket(type=socket.SOCK_DGRAM)\n sock.connect(('127.0.0.1', 7777))\n - |\n # Write stuff to UDP socket\n for msg in messages:\n sock.send('json:{}\\n'.format(msg[3].replace(r'\\n', ' ')).encode('u8'))\n\nTcl\n'''\n\n`Tcl` code can be one block or be split into an initialization section and a runtime section. The former is executed\nonce at startup and is intended to contain stuff like ``proc`` statements. The latter is run for every\nevent.\n\nIn `Tcl`, the following variables are available:\n\n**logfile**\n The path of the logfile where the event was coming from\n**messages**\n A list of lists. For each event the inner list contains:\n - a bool which is True if the entry is a context line\n - the sequence number\n - an int with a timestamp\n - a string with the message text\n\nExample::\n\n do:\n tcl: |\n foreach m $messages {\n puts \"$logfile: [clock format [expr int([lindex $m 2])]] [lindex $m 3]\"\n }\n\nExample with initialization::\n\n do:\n tcl:\n - |\n proc output {m} {\n puts $m\n }\n - |\n foreach m $messages {\n output \"$logfile: [clock format [expr int([lindex $m 2])]] [lindex $m 3]\"\n }\n\nBash and sh\n'''''''''''\n\nIn `bash` and `sh`, the following variables are available:\n\n**logfile**\n The path of the logfile where the event was coming from\n**iscontext**\n An array with an int for every line where 1 means it is a context line or 0 otherwise\n**seqno**\n An array containing the sequence number for every line\n**time**\n An array containing the timestamp in ISO format for every line\n**message**\n An array containing the text for every line\n\nExample::\n\n do:\n bash: |\n echo $logfile: ${time[-1]} ${message[-1]}\n\nBut since `bash` is the default language, it can be written as::\n\n do: |\n echo $logfile: ${message[-1]}\n\nThe `do` clause can be omitted altogether in which case a default of ::\n\n do:\n python: |\n for msg in messages:\n print('%s: %s' % (logfile, msg[3]))\n\nis assumed.\n\nRunning\n-------\n\nCommand synopsis:\n ``lognotify`` [-h] --config `CONFIG` [--full]\n [--burst `BURST` | --force-burst `FORCE_BURST`]\n [--context `CONTEXT`] [--debug] [--version]\n logfile [logfile ...]\n\nPositional arguments:\n `logfile`\n A log file to scan\n\nOptional arguments:\n -h, --help show this help message and exit\n --config CONFIG, -c CONFIG specify config file\n --full, -f scan files from beginning\n --burst BURST, -b BURST report bursts of BURST seconds together\n --force-burst FORCE_BURST, -B FORCE_BURST\n force reporting bursts of BURST seconds together\n --context CONTEXT, -C CONTEXT\n specify context size\n --debug, -d Print some debug information to stderr\n --version, -v display version and exit\n\nAt least one path to an existing, readable log file is expected.\n\nThe ``--full`` or ``-f`` option requests reading files from the start. Without the flag, reading begins at the current\nend of file. Sequence numbering always begins from the point where reading begins.\n\nThe ``--debug`` or ``-d`` option sends information to the standard error file. Repeating the flag increases the\namount of information.\n\nUseful scripts\n--------------\n\nThis section is a collection of useful scripts.\n\nSend desktop notification\n.........................\n\nTo be used as root (change ``'username'`` accordingly)::\n\n from subprocess import check_call\n\n check_call(\n [\n 'su', 'username', '-c',\n 'DISPLAY=:0 notify-send \"%s\" \"%s\"' % (logfile, '\\n'.join('> '[m[0]] + m[3] for m in messages))\n ]\n )\n\nSend desktop notification to remote machine\n...........................................\n\nTo be used as root (change ``'hostname'`` and ``username`` accordingly)::\n\n from subprocess import check_call\n from platform import node\n\n check_call(\n [\n 'ssh', 'hostname',\n r'su username -c \"DISPLAY=:0 notify-send \\\"%s: %s\\\" \\\"%s\\\"\"' % (\n node(),\n logfile,\n '\\n'.join('! '[m[0]] + m[3] for m in messages)\n )\n ]\n )\n\nSend e-mail\n...........\n\nChange ``'mail-user'``, ``'mail-user-password'``, ``source-email`` and ``destination-email`` accordingly::\n\n do:\n python: |\n from smtplib import SMTP\n import sys\n\n client = SMTP('localhost')\n try:\n client.starttls()\n except:\n pass\n client.login('mail-user', 'mail-user-password')\n client.sendmail(\n 'source-email',\n 'destination-email',\n 'From: source-email\\n'\n 'To: destination-email\\n'\n 'Subject: Message in %s\\n\\n'\n '%s\\n' % (logfile, '\\n'.join('> '[m[0]] + m[3] for m in messages))\n )", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://pypi.python.org/pypi/jw.lognotify", "keywords": "logfile notifications", "license": "GPL", "maintainer": null, "maintainer_email": null, "name": "jw.lognotify", "package_url": "https://pypi.org/project/jw.lognotify/", "platform": "Posix", "project_url": "https://pypi.org/project/jw.lognotify/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://pypi.python.org/pypi/jw.lognotify" }, "release_url": "https://pypi.org/project/jw.lognotify/0.3/", "requires_dist": null, "requires_python": null, "summary": "Notify about logfile events in real-time", "version": "0.3" }, "last_serial": 1925666, "releases": { "0.1.1": [], "0.1.2": [ { "comment_text": "", "digests": { "md5": "76076294b437886b3c25b3cd43a92d59", "sha256": "14d061e6101be5d9af01a2683555013a1b34cb0ebe672799fb1ab93b1e9aee56" }, "downloads": -1, "filename": "jw.lognotify-0.1.2.tar.gz", "has_sig": false, "md5_digest": "76076294b437886b3c25b3cd43a92d59", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8497, "upload_time": "2015-11-22T22:25:11", "url": "https://files.pythonhosted.org/packages/17/df/5f1b2c20f3cf56cc809000d2f67cbaddcc15a1b5ee661240ba6857ac9fbc/jw.lognotify-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "49ee841a66e0cc5cc5bb24f6427287c8", "sha256": "78c2ce6017ae51e92cead7a0f54bcc02f980c6e7cde125e11f84a177c6b3b364" }, "downloads": -1, "filename": "jw.lognotify-0.1.3.tar.gz", "has_sig": false, "md5_digest": "49ee841a66e0cc5cc5bb24f6427287c8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9652, "upload_time": "2015-11-26T10:27:45", "url": "https://files.pythonhosted.org/packages/ed/6f/2adcb13cab9b2edc51f4e6bda011082368a3401345b3d4c7007a2b88cfd6/jw.lognotify-0.1.3.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "0f339778071aa71e588460bfbadfab68", "sha256": "ece6d3ec32ae95ac135ca21c355a61bd3ad2e37593d75f133e95bcb5feb9f7ac" }, "downloads": -1, "filename": "jw.lognotify-0.2.tar.gz", "has_sig": false, "md5_digest": "0f339778071aa71e588460bfbadfab68", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14782, "upload_time": "2015-11-30T00:59:57", "url": "https://files.pythonhosted.org/packages/7e/cf/8815f5754c6ba5cdd14c4bda3998f237dc6fe9081e19c638e30f28af8500/jw.lognotify-0.2.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "4b7a683e1903e36657ac241db5c97c16", "sha256": "921d8f85512520c1fe3f0bfe663996032e1c60c606798a1ad0681373d3726f3e" }, "downloads": -1, "filename": "jw.lognotify-0.2.2.tar.gz", "has_sig": false, "md5_digest": "4b7a683e1903e36657ac241db5c97c16", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11955, "upload_time": "2015-11-30T13:48:02", "url": "https://files.pythonhosted.org/packages/cc/d7/b18ebdd62098f5b95c4383f422c13ce3a817875aeff82fb6a0e1f0009686/jw.lognotify-0.2.2.tar.gz" } ], "0.2.3": [ { "comment_text": "", "digests": { "md5": "f3704ce5077626c2d8071eff1ce4c790", "sha256": "075c109570100dae0c6eec7e9e0d637f17348f8f12f4c2dd0f7c819cde34a9b4" }, "downloads": -1, "filename": "jw.lognotify-0.2.3.tar.gz", "has_sig": false, "md5_digest": "f3704ce5077626c2d8071eff1ce4c790", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14375, "upload_time": "2016-01-20T23:42:35", "url": "https://files.pythonhosted.org/packages/d6/fa/7c8b69bee865bcc7e8524ea228b07b029223bdbf3ff9644cc6010784a3e6/jw.lognotify-0.2.3.tar.gz" } ], "0.2.5": [ { "comment_text": "", "digests": { "md5": "3da12f5686f9294e92bd9a6508ad07af", "sha256": "0c2adfd6ab9864d496542c32bcd4a41835c2e14bb10dc319f268c56b424dc074" }, "downloads": -1, "filename": "jw.lognotify-0.2.5.tar.gz", "has_sig": false, "md5_digest": "3da12f5686f9294e92bd9a6508ad07af", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16000, "upload_time": "2016-01-21T23:58:28", "url": "https://files.pythonhosted.org/packages/c6/85/75bb5290712eb5fde6cca3bfe2e874b1241889f96a797a4968dfec4cded1/jw.lognotify-0.2.5.tar.gz" } ], "0.2.6": [ { "comment_text": "", "digests": { "md5": "e356c5625d2581dae8351c31df7166c7", "sha256": "16796f73d724f50c880aace5fcfb28125d00adbcfcef49c2406b3efccfb7feec" }, "downloads": -1, "filename": "jw.lognotify-0.2.6.tar.gz", "has_sig": false, "md5_digest": "e356c5625d2581dae8351c31df7166c7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16267, "upload_time": "2016-01-23T09:47:10", "url": "https://files.pythonhosted.org/packages/e0/59/ed07c672235746cfe8571f6c2f1f047103a7d56b033cac802f459d5c207d/jw.lognotify-0.2.6.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "66596f80685ec49fdacb2681e99d64a3", "sha256": "20bf3447d182d88d9e0d4a662b57d33e4aa31720e62ace87aaaf959fc4ce2fbf" }, "downloads": -1, "filename": "jw.lognotify-0.3.tar.gz", "has_sig": false, "md5_digest": "66596f80685ec49fdacb2681e99d64a3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14118, "upload_time": "2016-01-27T14:44:16", "url": "https://files.pythonhosted.org/packages/36/55/7441bc4024286d2b85f7e18b1d3a702c73b8dc152ff17efedde8bc1b1262/jw.lognotify-0.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "66596f80685ec49fdacb2681e99d64a3", "sha256": "20bf3447d182d88d9e0d4a662b57d33e4aa31720e62ace87aaaf959fc4ce2fbf" }, "downloads": -1, "filename": "jw.lognotify-0.3.tar.gz", "has_sig": false, "md5_digest": "66596f80685ec49fdacb2681e99d64a3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14118, "upload_time": "2016-01-27T14:44:16", "url": "https://files.pythonhosted.org/packages/36/55/7441bc4024286d2b85f7e18b1d3a702c73b8dc152ff17efedde8bc1b1262/jw.lognotify-0.3.tar.gz" } ] }