Skip to content

Commit 7876f42

Browse files
authored
Merge pull request #13 from CodersOfTheNight/master
Release 0.2
2 parents df992bf + c134c94 commit 7876f42

File tree

18 files changed

+500
-49
lines changed

18 files changed

+500
-49
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
language: python
22
python:
33
- 3.5
4+
- 3.6
45

56
install:
67
- pip install -r requirements/release.txt

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ How to install
2626
==============
2727
`pip install oshino`
2828

29+
Quickstart
30+
==========
31+
It is highly recommended for new users to use [Quickstart Guide](quickstart.md)
32+
33+
2934
Riemann. What? Why? How?
3035
=========================
3136
Riemann is a backbone of this system. It does alerting, it receives metrics, it aggregates metrics and it decides where to send them (eg.: Graphite, Logstash).

docs/agents.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
What is "Agent"?
2+
-----------------
3+
In this context, we call a worker which collects specific type of metrics, an agent.
4+
5+
How to use them
6+
--------------
7+
To be able to use any of agents, first you must import them.
8+
Importing is done via config, by adding them under `agents` section
9+
10+
11+
An example config could look like this:
12+
```yaml
13+
---
14+
interval: 10
15+
loglevel: DEBUG
16+
riemann:
17+
host: localhost
18+
port: 5555
19+
transport: BlankTransport
20+
agents:
21+
- name: echo
22+
module: oshino.agents.subprocess_agent.SubprocessAgent
23+
script: "echo 'Hello world!'"
24+
tag: "bash"
25+
```
26+
27+
More configuration info can be found under [Config](config.md)
28+
29+
As you can see, there's one agent in agents array, which is called `echo`
30+
and uses internal `SubprocessAgent` class.
31+
This type of agent is able to execute command in command line
32+
and return it's result as a metric.
33+
34+
Internal agents also includes `HttpAgent` which is able to do HTTP calls,
35+
and returns response and time it took to execute as metrics.
36+
37+
Usual source of agents is [Third Party agent section](thirdparty.md)
38+
They can be installed via `pip` command, or using `oshino-admin`.
39+
For more information on `oshino-admin` usage, do `oshino-admin --help`.
40+
41+
42+
Creating custom Agent
43+
---------------------
44+
It can be done by using our [Cookiecutter Template](https://github.com/CodersOfTheNight/oshino-cookiecutter)

docs/augments.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
What is "Augment"?
2+
------------------
3+
In this context, we a process which reads specific metrics and produces new ones, we call an augment.
4+
Augment's job is to produce additional insights from metrics we already have.
5+
6+
How to use them?
7+
----------------
8+
You need to include specific augment inside config under augments array, very similar to [Agents](agents.md).
9+
10+
An example config could look like this:
11+
```yaml
12+
---
13+
interval: 10
14+
loglevel: DEBUG
15+
riemann:
16+
host: localhost
17+
port: 5555
18+
transport: BlankTransport
19+
augments:
20+
- name: moving average
21+
key: cpu
22+
module: oshino.augments.stats.SimpleMovingAverage
23+
step: 5
24+
tag: "sma"
25+
```
26+
27+
More configuration info can be found under [Config](config.md)

docs/config.md

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Base Config
2-
-----------
2+
============
33
- `interval` - how often to send metrics (in seconds)
44
- `riemann.host` - riemann hostname (default: localhost)
55
- `riemann.port` - riemann port (default: 5555)
@@ -8,28 +8,47 @@ Base Config
88
- `sentry-dsn` - sentry address for error reporting (default: `None`)
99
- `executor` - allows to define executor class, default one is `concurrent.futures.ThreadPoolExecutor`
1010
- `executors-count` - set worker count for executor, default: 10
11+
- `agents` - an array of agent configs used in this setup
12+
- `augments` - an array of augment configs used in this setup
13+
14+
Agents
15+
=======
1116

1217
General Config for Agents
1318
------------------------
19+
- `name`- give name for agent
1420
- `tag` - adds this tag to all metrics related to this agent
21+
- `module` - path to module from which actual agent should be loaded. In most cases this path should be declared in actor's README
1522

1623
Http Agent Config
1724
----------------
25+
Agent used to produce HTTP calls to specific website
26+
module: `oshino.agents.http_agent.HttpAgent`
27+
1828
- `url` - which url to call
1929

2030
Subprocess Agent Config
2131
-----------------------
32+
Agent used to execute CLI scripts
33+
module: `oshino.agents.subprocess_agent.SubprocessAgent`
34+
2235
- `script` - what shell script to execute
2336

2437

25-
Suggested Riemann config
26-
-------------------------
27-
```clojure
28-
(where (tagged-all ["oshino", "heartbeat"])
29-
(changed :state
30-
(email "something@something.com")
31-
)
32-
)
33-
```
38+
Augments
39+
========
40+
41+
General config for Augments
42+
---------------------------
43+
- `name`- give name for augment
44+
- `key` - defines a metric key to listen to
45+
- `tag` - adds this tag to all metrics related to this augment
46+
- `module` - path to module from which actual augment should be loaded. In most cases this path should be declared in augment's README
47+
48+
49+
Moving Average
50+
--------------
51+
Reads metrics and produces moving average
52+
module: `oshino.augments.stats.MovingAverage`
3453

35-
If Oshino goes down, or encounters some performance hickups - you'll be notified
54+
- `step` - how much metrics it should inhale before it can produce average

docs/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
Table of Contents:
22
==================
3+
- [Quickstart](quickstart.md)
34
- [Installiation](install.md)
45
- [Riemann](riemann.md)
56
- Usage
67
- [Events](events.md)
78
- [Config](config.md)
89
- Extending
10+
- [Agents](agents.md)
11+
- [Augments](augments.md)
912
- [Third Party Agents](thirdparty.md)

docs/quickstart.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
Preparing Environment
2+
======================
3+
You will need Python version 3.5+ and `pip` installed.
4+
In the most cases `pip` should come bundled, if building from source, you will need to have `openssl` development package installed, otherwise it will skip.
5+
6+
If for some reason you don't have it and cannot build with `openssl`, there's always:
7+
8+
`wget https://bootstrap.pypa.io/get-pip.py | python`
9+
10+
Virtualenv
11+
----------
12+
It is optional, but highly recommended.
13+
Can be installed via `pip install virtualenv`
14+
15+
To create actual virtualenv, do:
16+
`virtualenv venv`
17+
Or if you have multiple versions of python (usually 2.7 and 3.****),
18+
failproof approach would be:
19+
`python3 -m virtualenv venv`
20+
21+
This will create virtual environment inside folder
22+
23+
Depending on OS, activating environment may slightly differ.
24+
Linux/MacOS/*BSD it is `source venv/bin/activate`
25+
Windows: `venv\Scripts\activate`
26+
27+
Installing Oshino
28+
-----------------
29+
When everything is prepared, installing is as easy as:
30+
`pip install oshino`
31+
32+
33+
Launching Oshino
34+
================
35+
First create config. Easy way to do that is by using `oshino-admin`
36+
37+
`oshino-admin config init config.yaml`
38+
39+
And now you can actually start it:
40+
`oshino --config=config.yaml`
41+
42+
Running as daemon
43+
------------------
44+
To start as a daemon, we need to use `oshino-admin`
45+
`oshino-admin start --config=config.yaml`
46+
47+
If you're running on your local machine or not as root, it's possible to get error like:
48+
`Unable to create the pidfile.`
49+
By default it writes PID (Process ID) file to `/var/run/oshino.pid` and permissions are not always sufficient to do that.
50+
Issue can be easily mitigated by providing custom path:
51+
`oshino-admin start --config=config.yaml --pid=oshino.pid`
52+
53+
To check if it's running:
54+
`oshino-admin status`
55+
56+
To stop it:
57+
`oshino-admin stop`
58+
59+
Main caveat in using custom pid path, you need to provide it for `status` and `stop` commands as well:
60+
61+
`oshino-admin status --pid=oshino.pid`
62+
`oshino-admin stop --pid=oshino.pid`
63+
64+
65+
Installing plugins
66+
==================
67+
68+
In the most cases, these plugins are for agents. Agent in Oshino context is metrics collector.
69+
So for example, if our service is using [Prometheus](https://prometheus.io/) and we want to collect metrics from it,
70+
plugin needs to be installed:
71+
72+
`oshino-admin plugin install oshino_prometheus`
73+
74+
To list available plugins:
75+
`oshino-admin plugin list`
76+
77+
Plugin can be removed via `uninstall` command:
78+
79+
`oshino-admin plugin uninstall oshino_statsd`
80+
81+
Making sense of Config
82+
=======================
83+
Generated config should look like this:
84+
85+
```yaml
86+
---
87+
interval: 10
88+
riemann:
89+
host: localhost
90+
port: 5555
91+
agents:
92+
- name: health-check
93+
module: oshino.agents.http_agent.HttpAgent
94+
url: http://python.org
95+
tag: healthcheck
96+
```
97+
98+
It says, that `interval` at which metrics will be pushed is 10 seconds,
99+
it is expecting Riemann at `localhost:5555`
100+
And currently has one Agent called `health-check` which uses included `HttpAgent`
101+
to do a healthcheck on `http://python.org`. Resulting metrics are tagged `healthcheck`
102+
103+
More info can be found on: [Config](config.md) section.
104+
105+
In general, a proper Riemann's address needs to be providen and array of agents extended
106+
with agents you require

docs/thirdparty.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,3 @@ Known agents:
1010
- [oshino-hw](https://github.com/CodersOfTheNight/oshino-hw)
1111
- [oshino-prometheus](https://github.com/CodersOfTheNight/oshino-prometheus)
1212

13-
Creating custom Agent
14-
---------------------
15-
It can be done by using our [Cookiecutter Template](https://github.com/CodersOfTheNight/oshino-cookiecutter)

oshino/augments/__init__.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from time import time
2+
3+
from oshino.config import TagMixin
4+
5+
6+
class AugmentBase(TagMixin):
7+
def __init__(self, data):
8+
self._data = data
9+
10+
def activate(self, client, g):
11+
pass
12+
13+
def is_valid(self):
14+
return True
15+
16+
@property
17+
def name(self):
18+
return self._data["name"].lower().replace(" ", "-")
19+
20+
@property
21+
def prefix(self):
22+
return "{0}.".format(self.name)
23+
24+
@property
25+
def key(self):
26+
return self._data["key"]
27+
28+
def send_event(self, client, **kwargs):
29+
tags = [self.tag] if self.tag else []
30+
if "tags" in kwargs:
31+
for tag in tags:
32+
kwargs["tags"].append(tag)
33+
else:
34+
kwargs["tags"] = tags
35+
36+
if "time" not in kwargs:
37+
kwargs["time"] = int(time())
38+
39+
client.event(**kwargs)
40+
41+
42+
def consume(q):
43+
while not q.empty():
44+
yield q.get()
45+
46+
47+
class InvalidAugment(AugmentBase):
48+
"""
49+
Only for Testing purposes
50+
"""
51+
52+
def is_valid(self):
53+
return False
54+
55+
def activate(self, client, g):
56+
raise RuntimeError("We shouldn't get here!")

oshino/augments/stats.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from collections import deque
2+
3+
from . import AugmentBase
4+
5+
6+
class SimpleMovingAverage(AugmentBase):
7+
8+
def __init__(self, *args, **kwargs):
9+
super(SimpleMovingAverage, self).__init__(*args, **kwargs)
10+
self.dq = deque(maxlen=self.step)
11+
12+
@property
13+
def step(self):
14+
return self._data.get("step", 5)
15+
16+
def activate(self, client, g):
17+
step = self.step
18+
19+
stopped = False
20+
while not stopped:
21+
22+
try:
23+
event = next(g)
24+
self.dq.append(event)
25+
except StopIteration:
26+
stopped = True
27+
break
28+
29+
data = list(map(lambda x: x["metric_f"], list(self.dq)))
30+
if len(data) == step:
31+
output = sum(data) / len(data)
32+
33+
self.send_event(client,
34+
service=self.prefix + "value",
35+
metric_f=output,
36+
state="ok")

0 commit comments

Comments
 (0)