Skip to content

Commit

Permalink
Major update
Browse files Browse the repository at this point in the history
- Added Command Line Args
- Made the docs better
- Added Filtering possibilities
- Made installation file work
  • Loading branch information
RandyParedis committed May 24, 2020
1 parent 0182baa commit e5db283
Show file tree
Hide file tree
Showing 13 changed files with 486 additions and 123 deletions.
94 changes: 94 additions & 0 deletions Filter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
## Filtering of Messages

Often, one would like to obtain information about specific messages. This can
be done by filtering the messages. In the "_Filter_" box, you can provide an
expression, indicative of the filter you would like.

These filters are case-insensitive, unless when searching for a string.

#### Expressions
Each filter consists of a set of boolean expressions, which can be combined
using the `and` and `or` operators. An expression can be negated
by adding the unary `not` operator to the front.

The expressions are solved from left to right. If parentheses are used to
group multiple expressions together, all groups are solved first.

In total, there are eight binary operators and one unary operator, as defined
in the table below. The first column defines the name for the operator, the
second identifies how the operator works and the third provides the meaning.

| Operator | Syntax | Sematics |
|:---:|:---:|:---|
| Less Than | `a < b` or `a lt b` | Yields true if `a` is less than `b` |
| Less Than or Equals | `a <= b` or `a le b` | Yields true if `a` is less than or equal to `b` |
| Greater Than | `a > b` or `a gt b` | Yields true if `a` is greater than `b` |
| Greater Than or Equals | `a >= b` or `a ge b` | Yields true if `a` is greater than or equal to `b` |
| Equals | `a == b` or `a eq b` or `a is b` | Yields true if `a` is equal to `b` |
| Not Equals | `a != b` or `a ne b` | Yields true if `a` is not equal to `b` |
| Not Equals | `a != b` or `a ne b` | Yields true if `a` is not equal to `b` |
| Containment | `a in b` | Yields true if `a` can be found in `b`. |
| And | `a and b` or `a && b` | Yields true if both `a` and `b` are true. |
| Or | `a or b` or <code>a &#124;&#124; b</code> | Yields true if either `a` or `b` is true. |
| Not | `not a` or `!a` | Negates the boolean value of `a`. |

#### Column Names
Obviously, it would make sense that we can select records based on column
values. To select a column, just type the column name (case insensitive).
E.g. selecting all records where the `ID` value lies between 0 and 10 can be
written as: `0 < id and id < 10`.

Note that `FACILITY` and `LEVEL` are evaluated numerically.

#### Strings and Numbers
You can use numbers in the filter box, following a normal format: they can be
negated, may have as many numbers behind the decimal as desired, but they
cannot start with a 0, _unless_ it is the only character before the decimal
place; i.e. `012.5` is invalid, use `12.5` instead. Furthermore, when using a
decimal, there *must* be a number before the decimal; i.e. `.156` is invalid,
use `0.156` instead. The full regular expression that matches numbers is:
`-?([1-9][0-9]*|0)(\.[0-9]*)?`

Strings can be used as well, as long as they are encapsulated in double quotes.
The `in`-operator can be used to check substrings.

#### Special Keywords
Specific colums might require specific values. These keywords are summarized
below. They are all case-insensitive.

| Keyword | Meaning |
| :---:|:---|
| `today` | Today's timestamp (ignoring the time). |
| `now` | The current time, ignoring the microseconds. |
| `emergency` or `emerg` | The numerical value of the `EMERGENCY` level. |
| `alert` | The numerical value of the `ALERT` level. |
| `critical` | The numerical value of the `CRITICAL` level. |
| `error` | The numerical value of the `ERROR` level. |
| `warning` | The numerical value of the `WARNING` level. |
| `notice` | The numerical value of the `NOTICE` level. |
| `info` or `information` | The numerical value of the `INFO` level. |
| `debug` | The numerical value of the `DEBUG` level. |
| `kernel` | The numerical value of the `Kernel` facility. |
| `userlevel` | The numerical value of the `User-Level` facility. |
| `mailsystem` | The numerical value of the `Mail System` facility. |
| `systemdaemons` | The numerical value of the `System Daemons` facility. |
| `security1` | The numerical value of the `Security 1` facility. |
| `internal` | The numerical value of the `Internal` facility. |
| `lineprinter` | The numerical value of the `Line Printer` facility. |
| `networknews` | The numerical value of the `Network News` facility. |
| `uucp` | The numerical value of the `UUCP` facility. |
| `clockdaemon` | The numerical value of the `Clock Daemon` facility. |
| `security2` | The numerical value of the `Security 2` facility. |
| `ftpdaemon` | The numerical value of the `FTP Daemon` facility. |
| `ntp` | The numerical value of the `NTP` facility. |
| `logaudit` | The numerical value of the `Log Audit` facility. |
| `logalert` | The numerical value of the `Log Alert` facility. |
| `scheduling` | The numerical value of the `Scheduling` facility. |
| `local0` | The numerical value of the `Local 0` facility. |
| `local1` | The numerical value of the `Local 1` facility. |
| `local2` | The numerical value of the `Local 2` facility. |
| `local3` | The numerical value of the `Local 3` facility. |
| `local4` | The numerical value of the `Local 4` facility. |
| `local5` | The numerical value of the `Local 5` facility. |
| `local6` | The numerical value of the `Local 6` facility. |
| `local7` | The numerical value of the `Local 7` facility. |
66 changes: 57 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,74 @@
# PySysLogQt
Extremely simple `syslog` viewer written in `Python 3`.
Extremely simple `syslog` server written in `Python 3`, for those who do not
want to install a complex `syslog` server, or write their own.

**Note: It is nothing too fancy at this point in time. Currently, there are
no intentions of making this quite extensive. Features may be requested in the
_Issues_ page.**
## Features:
* Lightweight and graphical!
* Accepts messages according to the `RFC 5424` format, but also allows the
simplified `Python`-format (`<PRI>MESSAGE\000`)!
* Save the messages to a file for later use!
* Load a file of previously saved messages!
* Sort all messages!
* Filter all messages with [complex filters](./Filter.md)!
* Color-coded records for all severity levels!
* Hide unwanted information!

## Requirements:
* `PyQt5`
* `lark-parser`
* `rfc5424-logging-handler`
* `dateutil`

## Execution
### Run from Source
Make sure you have `Python 3` and `PyQt5` installed.
#### Command Line Arguments
`PySysLogQt` can be launched with command line arguments. Use the `-h` or
the `--help` flag to get the help menu:
```
usage: PySysLogQt [-h] [-H [HOST]] [-P [PORT]] [-c]
Starts a syslog server.
optional arguments:
-h, --help show this help message and exit
-H [HOST], --host [HOST]
The host to listen on. Defaults to "localhost".
-P [PORT], --port [PORT]
The port to listen on. Defaults to 1024.
-c, --cli When set, the command line interface is used over the
GUI.
```
#### Run from Source
Make sure you have `Python 3` and all requirements installed.
In the root directory, execute
```bash
python3 __main__.py
python3 __main__.py -h
```

### Run from Executable
Note that this gives the `help`-menu.

#### Run from Executable
For Linux-systems, an executable is bundled for simplicity of use. This file
is located in the `dist` folder, or can be downloaded from the latest version.

## Allow all Ports
#### Load a File on Launch
When setting the `HOST` to `file://<myfile>`, the server will not listen to
traffic, but instead open the file called `<myfile>`. The port will be
ignored in this case. Note that, the first two slashes are **not** part of
the filename.

## Issues
#### Allow all Ports
By default, all ports below 1024 (with the exception of port 0) require root
access. Execute the application as such to be able to capture all those
messages.

Capturing on port 0 is disallowed, since it commonly indicates "_choose any
valid port_".

#### Not seeing your messages?
It is perfectly possible that your messages are not being displayed. Make
sure:
* The `host` and `port` are set to the correct source.
* The logger is not muting the messages. Often, `WARNING` messages are set to
be the lowest level of messages that are sent, implicitly muting all
`DEBUG`, `INFO` and `NOTICE` messages.
33 changes: 27 additions & 6 deletions __main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,36 @@

from PyQt5 import QtWidgets
from main.MainWindow import MainWindow
from main.pysyslog import setup
import sys


if __name__ == '__main__':
import argparse
NAME = "PySysLogQt"
app = QtWidgets.QApplication(sys.argv)
app.setApplicationName(NAME)
app.setApplicationDisplayName(NAME)

mainwindow = MainWindow()
mainwindow.show()
code = app.exec_()
parser = argparse.ArgumentParser(prog=NAME, description='Starts a syslog server.')
parser.add_argument('-H', '--host', dest='host', type=str, nargs='?', const='localhost',
help='The host to listen on. Defaults to "localhost".')
parser.add_argument('-P', '--port', dest='port', type=int, nargs='?', const=1024,
help='The port to listen on. Defaults to 1024.')
parser.add_argument('-c', '--cli', dest='cli', action='store_true',
help='When set, the command line interface is used over the GUI.')
args = parser.parse_args(sys.argv[1:])

if args.cli:
host = args.host
port = args.port
if host is None:
host = "localhost"
if port is None:
port = 1024
setup(host, port)
else:
app = QtWidgets.QApplication(sys.argv)
app.setApplicationName(NAME)
app.setApplicationDisplayName(NAME)

mainwindow = MainWindow(args.host, args.port)
mainwindow.show()
code = app.exec_()
4 changes: 3 additions & 1 deletion install.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pyinstaller -n PySysLogQt --onefile --windowed __main__.py
pyinstaller -n PySysLogQt --onefile --windowed \
--add-data ./vendor:vendor/ \
__main__.py
63 changes: 63 additions & 0 deletions main/Extra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""This file contains variables and functions that can be called from anywhere.
Author: Randy Paredis
Date: 05/24/2020
"""

import sys, os

LEVELS = {
0: "EMERGENCY",
1: "ALERT",
2: "CRITICAL",
3: "ERROR",
4: "WARNING",
5: "NOTICE",
6: "INFO",
7: "DEBUG"
}

RLEVELS = { LEVELS[k]:k for k in LEVELS }
RLEVELS["EMERG"] = 0
RLEVELS["INFORMATION"] = 6

FACS = {
0: "Kernel",
1: "User-Level",
2: "Mail System",
3: "System Daemons",
4: "Security 1",
5: "Internal",
6: "Line Printer",
7: "Network News",
8: "UUCP",
9: "Clock Daemon",
10: "Security 2",
11: "FTP Daemon",
12: "NTP",
13: "Log Audit",
14: "Log Alert",
15: "Scheduling",
16: "Local 0",
17: "Local 1",
18: "Local 2",
19: "Local 3",
20: "Local 4",
21: "Local 5",
22: "Local 6",
23: "Local 7"
}

RFACS = { FACS[k]:k for k in FACS}



def resource_path(*relative_paths):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except:
base_path = os.path.abspath(".")

return os.path.join(base_path, *relative_paths)
Loading

0 comments on commit e5db283

Please sign in to comment.