From 6e8f44661e62b6de4576f342195005537db91e3a Mon Sep 17 00:00:00 2001 From: Nikita Grishko Date: Fri, 21 Feb 2020 15:15:43 +0300 Subject: [PATCH] [feature] add documentation (#18) --- .github/workflows/release-created.yml | 34 ++++++++- CHANGELOG.md | 1 + Makefile | 8 ++ README.md | 40 ++-------- aiodogstatsd/contrib/aiohttp.py | 2 + aiodogstatsd/contrib/sanic.py | 2 + docs/frameworks/aiohttp.md | 39 ++++++++++ docs/frameworks/sanic.md | 46 ++++++++++++ docs/frameworks/starlette.md | 34 +++++++++ docs/index.md | 42 +++++++++++ docs/usage.md | 101 ++++++++++++++++++++++++++ mkdocs.yml | 29 ++++++++ pyproject.toml | 2 + 13 files changed, 345 insertions(+), 35 deletions(-) create mode 100644 docs/frameworks/aiohttp.md create mode 100644 docs/frameworks/sanic.md create mode 100644 docs/frameworks/starlette.md create mode 100644 docs/index.md create mode 100644 docs/usage.md create mode 100644 mkdocs.yml diff --git a/.github/workflows/release-created.yml b/.github/workflows/release-created.yml index e96bd2d..91b1ec8 100644 --- a/.github/workflows/release-created.yml +++ b/.github/workflows/release-created.yml @@ -5,7 +5,32 @@ on: types: [created] jobs: - build: + build-docs: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v1 + with: + python-version: 3.8 + - uses: Gr1N/setup-poetry@v1 + with: + poetry-version: 1.0.0 + - uses: actions/cache@v1 + with: + path: ~/.cache/pypoetry/virtualenvs + key: ${{ runner.os }}-3.8-poetry-${{ hashFiles('pyproject.toml') }} + restore-keys: | + ${{ runner.os }}-3.8-poetry- + - run: make install-deps + - run: make docs-build + - uses: peaceiris/actions-gh-pages@v2 + env: + PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }} + PUBLISH_BRANCH: gh-pages + PUBLISH_DIR: ./site + + build-package: runs-on: ubuntu-latest steps: @@ -27,6 +52,13 @@ jobs: env: PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }} PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + + build-notify: + runs-on: ubuntu-latest + + needs: [build-docs, build-package] + + steps: - uses: appleboy/telegram-action@0.0.7 with: to: ${{ secrets.TELEGRAM_CHAT_ID }} diff --git a/CHANGELOG.md b/CHANGELOG.md index a3f49b0..45e07e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Updated documentation: described why 9125 port used by default, #16 - Added [`Starlette`](https://www.starlette.io) framework integration helpers (middleware), #15 - Fixed futures initialization. From this time futures always initialized in the same event loop, #15 +- Added [documentation](https://gr1n.github.io/aiodogstatsd), #18 ## 0.10.0 (2019-12-03) diff --git a/Makefile b/Makefile index 77597ed..e68ca43 100644 --- a/Makefile +++ b/Makefile @@ -53,3 +53,11 @@ codecov: .PHONY: publish publish: @$(POETRY) publish --username=$(PYPI_USERNAME) --password=$(PYPI_PASSWORD) --build + +.PHONY: docs-serve +docs-serve: + @$(POETRY) run mkdocs serve + +.PHONY: docs-build +docs-build: + @$(POETRY) run mkdocs build diff --git a/README.md b/README.md index 72db210..62af86a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ An asyncio-based client for sending metrics to StatsD with support of [DogStatsD Library fully tested with [statsd_exporter](https://github.com/prometheus/statsd_exporter) and supports `gauge`, `counter`, `histogram`, `distribution` and `timing` types. -Note that client by default uses 9125 port, it's a default port for [statsd_exporter](https://github.com/prometheus/statsd_exporter) and it's different from 8125 which is used by default in StatsD and [DataDog](https://www.datadoghq.com/). Just initialize the client with the proper port you need if it's different from 9125. +`aiodogstatsd` client by default uses _9125_ port. It's a default port for [statsd_exporter](https://github.com/prometheus/statsd_exporter) and it's different from _8125_ which is used by default in StatsD and [DataDog](https://www.datadoghq.com/). Initialize the client with the proper port you need if it's different from _9125_. ## Installation @@ -16,36 +16,9 @@ Just type: $ pip install aiodogstatsd ``` -...or if you're interested in integration with [`AIOHTTP`](https://aiohttp.readthedocs.io/), [`Sanic`](https://sanicframework.org/) or [`Starlette`](https://www.starlette.io) frameworks specify corresponding extras: +## At a glance -```sh -$ pip install aiodogstatsd[aiohttp,sanic,starlette] -``` - -## Usage - -You can simply initialize client to send any metric you want: - -```python -import asyncio - -import aiodogstatsd - - -async def main(): - client = aiodogstatsd.Client() - await client.connect() - - client.increment("users.online") - - await client.close() - - -loop = asyncio.get_event_loop() -loop.run_until_complete(main()) -``` - -...or you can also use client as a context manager: +Just simply use client as a context manager and send any metric you want: ```python import asyncio @@ -55,14 +28,13 @@ import aiodogstatsd async def main(): async with aiodogstatsd.Client() as client: - client.increment("users.online") + client.increment("users.online") -loop = asyncio.get_event_loop() -loop.run_until_complete(main()) +asyncio.run(main()) ``` -Look at `examples/` to find more examples of library usage, e.g. integration with [`AIOHTTP`](https://aiohttp.readthedocs.io/), [`Sanic`](https://sanicframework.org/) or [`Starlette`](https://www.starlette.io) frameworks. +Please follow [documentation](https://gr1n.github.io/aiodogstatsd) or look at [`examples/`](https://github.com/Gr1N/aiodogstatsd/tree/master/examples) directory to find more examples of library usage, e.g. integration with [`AIOHTTP`](https://aiohttp.readthedocs.io/), [`Sanic`](https://sanicframework.org/) or [`Starlette`](https://www.starlette.io) frameworks. ## Contributing diff --git a/aiodogstatsd/contrib/aiohttp.py b/aiodogstatsd/contrib/aiohttp.py index bf20623..2eb9e43 100644 --- a/aiodogstatsd/contrib/aiohttp.py +++ b/aiodogstatsd/contrib/aiohttp.py @@ -30,6 +30,7 @@ def cleanup_context_factory( constant_tags: Optional[typedefs.MTags] = None, read_timeout: float = 0.5, close_timeout: Optional[float] = None, + sample_rate: typedefs.MSampleRate = 1, ) -> Callable[[web.Application], AsyncIterator[None]]: async def cleanup_context(app: web.Application) -> AsyncIterator[None]: app[client_app_key] = Client( @@ -39,6 +40,7 @@ async def cleanup_context(app: web.Application) -> AsyncIterator[None]: constant_tags=constant_tags, read_timeout=read_timeout, close_timeout=close_timeout, + sample_rate=sample_rate, ) await app[client_app_key].connect() yield diff --git a/aiodogstatsd/contrib/sanic.py b/aiodogstatsd/contrib/sanic.py index 6617084..0b2e0d0 100644 --- a/aiodogstatsd/contrib/sanic.py +++ b/aiodogstatsd/contrib/sanic.py @@ -35,6 +35,7 @@ def listeners_factory( constant_tags: Optional[typedefs.MTags] = None, read_timeout: float = 0.5, close_timeout: Optional[float] = None, + sample_rate: typedefs.MSampleRate = 1, ) -> Tuple[ListenerCallable, ListenerCallable]: async def listener_setup(app: Sanic, loop: AbstractEventLoop) -> None: client = Client( @@ -44,6 +45,7 @@ async def listener_setup(app: Sanic, loop: AbstractEventLoop) -> None: constant_tags=constant_tags, read_timeout=read_timeout, close_timeout=close_timeout, + sample_rate=sample_rate, ) await client.connect() diff --git a/docs/frameworks/aiohttp.md b/docs/frameworks/aiohttp.md new file mode 100644 index 0000000..57361b8 --- /dev/null +++ b/docs/frameworks/aiohttp.md @@ -0,0 +1,39 @@ +# AIOHTTP + +`aiodogstatsd` library can be easily used with [`AIOHTTP`](https://aiohttp.readthedocs.io/) web framework by using cleanup context and middleware provided. + +At first you need to install `aiodogstatsd` with required extras: + +```sh +pip install aiodogstatsd[aiohttp] +``` + +Then you can use code below as is to get initialized client and middleware: + +```python +from aiohttp import web + +from aiodogstatsd.contrib import aiohttp as aiodogstatsd + + +app = web.Application(middlewares=[aiodogstatsd.middleware_factory()]) +app.cleanup_ctx.append(aiodogstatsd.cleanup_context_factory()) +``` + +Optionally you can provide additional configuration to the cleanup context factory: + +- `client_app_key` — a key to store initialized `aiodogstatsd.Client` in application context (default: `statsd`); +- `host` — host string of your StatsD server (default: `localhost`); +- `port` — post of your StatsD server (default: `9125`); +- `namespace` — optional namespace string to prefix all metrics; +- `constant_tags` — optional tags dictionary to apply to all metrics; +- `read_timeout` (default: `0.5`); +- `close_timeout`; +- `sample_rate` (default: `1`). + +Optionally you can provide additional configuration to the middleware factory: + +- `client_app_key` — a key to lookup `aiodogstatsd.Client` in application context (default: `statsd`); +- `request_duration_metric_name` — name of request duration metric (default: `http_request_duration`); +- `collect_not_allowed` — collect or not `405 Method Not Allowed` responses; +- `collect_not_found` — collect or not `404 Not Found` responses. diff --git a/docs/frameworks/sanic.md b/docs/frameworks/sanic.md new file mode 100644 index 0000000..499bb5d --- /dev/null +++ b/docs/frameworks/sanic.md @@ -0,0 +1,46 @@ +# Sanic + +`aiodogstatsd` library can be easily used with [`Sanic`](https://sanicframework.org/) web framework by using listeners and middlewares provided. + +At first you need to install `aiodogstatsd` with required extras: + +```sh +pip install aiodogstatsd[sanic] +``` + +Then you can use code below as is to get initialized client and middlewares: + +```python +from sanic import Sanic + +from aiodogstatsd.contrib import sanic as aiodogstatsd + + +app = Sanic(name="aiodogstatsd") + +listener_setup, listener_close = aiodogstatsd.listeners_factory() +app.register_listener(listener_setup, "before_server_start") +app.register_listener(listener_close, "after_server_stop") + +middleware_req, middleware_resp = aiodogstatsd.middlewares_factory() +app.register_middleware(middleware_req, attach_to="request") +app.register_middleware(middleware_resp, attach_to="response") +``` + +Optionally you can provide additional configuration to the listeners factory: + +- `client_app_key` — a key to store initialized `aiodogstatsd.Client` in application context (default: `statsd`); +- `host` — host string of your StatsD server (default: `localhost`); +- `port` — post of your StatsD server (default: `9125`); +- `namespace` — optional namespace string to prefix all metrics; +- `constant_tags` — optional tags dictionary to apply to all metrics; +- `read_timeout` (default: `0.5`); +- `close_timeout`; +- `sample_rate` (default: `1`). + +Optionally you can provide additional configuration to the middlewares factory: + +- `client_app_key` — a key to lookup `aiodogstatsd.Client` in application context (default: `statsd`); +- `request_duration_metric_name` — name of request duration metric (default: `http_request_duration`); +- `collect_not_allowed` — collect or not `405 Method Not Allowed` responses; +- `collect_not_found` — collect or not `404 Not Found` responses. diff --git a/docs/frameworks/starlette.md b/docs/frameworks/starlette.md new file mode 100644 index 0000000..7c5f546 --- /dev/null +++ b/docs/frameworks/starlette.md @@ -0,0 +1,34 @@ +# Starlette + +`aiodogstatsd` library can be easily used with [`Starlette`](https://www.starlette.io) web framework by using client and middleware provided. + +At first you need to install `aiodogstatsd` with required extras: + +```sh +pip install aiodogstatsd[starlette] +``` + +Then you can use code below as is to get initialized client and middleware: + +```python +from starlette.applications import Starlette +from starlette.middleware import Middleware + +import aiodogstatsd +from aiodogstatsd.contrib.starlette import StatsDMiddleware + + +client = aiodogstatsd.Client() + +app = Starlette( + middleware=[Middleware(StatsDMiddleware, client=client)], + on_startup=[client.connect], + on_shutdown=[client.close], +) +``` + +Optionally you can provide additional configuration to the middleware: + +- `request_duration_metric_name` — name of request duration metric (default: `http_request_duration`); +- `collect_not_allowed` — collect or not `405 Method Not Allowed` responses; +- `collect_not_found` — collect or not `404 Not Found` responses. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..5406e9f --- /dev/null +++ b/docs/index.md @@ -0,0 +1,42 @@ +# aiodogstatsd + +[![Build Status](https://github.com/Gr1N/aiodogstatsd/workflows/default/badge.svg)](https://github.com/Gr1N/aiodogstatsd/actions?query=workflow%3Adefault) [![codecov](https://codecov.io/gh/Gr1N/aiodogstatsd/branch/master/graph/badge.svg)](https://codecov.io/gh/Gr1N/aiodogstatsd) ![PyPI](https://img.shields.io/pypi/v/aiodogstatsd.svg?label=pypi%20version) ![PyPI - Downloads](https://img.shields.io/pypi/dm/aiodogstatsd.svg?label=pypi%20downloads) ![GitHub](https://img.shields.io/github/license/Gr1N/aiodogstatsd.svg) + +`aiodogstatsd` is an asyncio-based client for sending metrics to StatsD with support of [DogStatsD](https://docs.datadoghq.com/developers/dogstatsd/) extension. + +Library fully tested with [statsd_exporter](https://github.com/prometheus/statsd_exporter) and supports `gauge`, `counter`, `histogram`, `distribution` and `timing` types. + +!!! info + `aiodogstatsd` client by default uses _9125_ port. It's a default port for [statsd_exporter](https://github.com/prometheus/statsd_exporter) and it's different from _8125_ which is used by default in StatsD and [DataDog](https://www.datadoghq.com/). Initialize the client with the proper port you need if it's different from _9125_. + +## Installation + +Just type: + +```sh +pip install aiodogstatsd +``` + +...or if you're interested in integration with [`AIOHTTP`](https://aiohttp.readthedocs.io/), [`Sanic`](https://sanicframework.org/) or [`Starlette`](https://www.starlette.io) frameworks specify corresponding extras: + +```sh +pip install aiodogstatsd[aiohttp,sanic,starlette] +``` + +## At a glance + +Just simply use client as a context manager and send any metric you want: + +```python +import asyncio + +import aiodogstatsd + + +async def main(): + async with aiodogstatsd.Client() as client: + client.increment("users.online") + + +asyncio.run(main()) +``` diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..1313a21 --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,101 @@ +# Usage + +## Basics + +`aiodogstatsd.Client` can be initialized with: + +- `host` — host string of your StatsD server (default: `localhost`); +- `port` — post of your StatsD server (default: `9125`); +- `namespace` — optional namespace string to prefix all metrics; +- `constant_tags` — optional tags dictionary to apply to all metrics; +- `read_timeout` (default: `0.5`); +- `close_timeout`; +- `sample_rate` (default: `1`). + +Below you can find an example of client initialization. Keep your eyes on lines 13 and 15. You always need to not to forget to initialize connection and close it at the end: + +```python hl_lines="13 15" +client = aiodogstatsd.Client( + host="127.0.0.1", + port=8125, + namespace="hello", + constant_tags={ + "service": "auth", + }, + read_timeout=0.5, + close_timeout=0.5, + sample_rate=1, +) + +await client.connect() +client.increment("users.online") +await client.close() +``` + +## Context manager + +As an option you can use `aiodogstatsd.Client` as a context manager. In that case you don't need to remember to initialize and close connection: + +```python +async with aiodogstatsd.Client() as client: + client.increment("users.online") +``` + +## Sending metrics + +### Gauge + +Record the value of a gauge, optionally setting `tags` and a `sample_rate`. + +```python +client.gauge("users.online", value=42) +``` + +### Increment + +Increment a counter, optionally setting a `value`, `tags` and a `sample_rate`. + +```python +client.increment("users.online") +``` + +### Decrement + +Decrement a counter, optionally setting a `value`, `tags` and a `sample_rate`. + +```python +client.decrement("users.online") +``` + +### Histogram + +Sample a histogram value, optionally setting `tags` and a `sample_rate`. + +```python +client.histogram("request.time", value=0.2) +``` + +### Distribution + +Send a global distribution value, optionally setting `tags` and a `sample_rate`. + +```python +client.distribution("uploaded.file.size", value=8819) +``` + +### Timing + +Record a timing, optionally setting `tags` and a `sample_rate`. + +```python +client.timing("query.time", value=0.5) +``` + +### TimeIt + +Context manager for easily timing methods, optionally settings `tags` and a `sample_rate`. + +```python +with client.timeit("query.time"): + ... +``` diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..349212f --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,29 @@ +site_name: aiodogstatsd +theme: + name: material + +repo_name: Gr1N/aiodogstatsd +repo_url: https://github.com/Gr1N/aiodogstatsd + +extra: + social: + - type: github + link: https://github.com/Gr1N + - type: linkedin + link: https://linkedin.com/in/ngrishko + +markdown_extensions: + - admonition + - codehilite: + guess_lang: false + linenums: true + - toc: + permalink: true + +nav: + - Home: index.md + - Usage: usage.md + - Frameworks: + - AIOHTTP: frameworks/aiohttp.md + - Sanic: frameworks/sanic.md + - Starlette: frameworks/starlette.md diff --git a/pyproject.toml b/pyproject.toml index 818faa0..b6c0229 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,7 @@ readme = "README.md" homepage = "https://github.com/Gr1N/aiodogstatsd" repository = "https://github.com/Gr1N/aiodogstatsd" +documentation = "https://gr1n.github.io/aiodogstatsd" keywords = ["asyncio", "statsd", "statsd-client", "statsd-metrics", "dogstatsd"] @@ -65,6 +66,7 @@ codecov = ">=2.0.15" flake8 = ">=3.7.6" flake8-bugbear = ">=18.8.0" isort = { version = ">=4.3.5", extras = ["pyproject"] } +mkdocs-material = ">=4.6" mypy = ">=0.670" pytest = ">=4.3.0" pytest-asyncio = ">=0.10.0"