Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

opentelemetry decorator #6

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions .dockerignore

This file was deleted.

77 changes: 69 additions & 8 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,96 @@ on:

jobs:
check:
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

runs-on: ubuntu-latest

env:
PYTHON_VERSION: python${{ matrix.python-version }}

steps:
- uses: actions/checkout@v4
- uses: "opensafely-core/setup-action@v1"
- uses: "opensafely-core/setup-action@v1.2.0"
with:
python-version: "3.11"
python-version: ${{ matrix.python-version }}
install-just: true
- name: Check formatting, linting and import sorting
run: just check

test:
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

runs-on: ubuntu-latest

env:
PYTHON_VERSION: python${{ matrix.python-version }}

steps:
- uses: actions/checkout@v4
- uses: "opensafely-core/setup-action@v1"
- uses: "opensafely-core/setup-action@v1.2.0"
with:
python-version: "3.11"
python-version: ${{ matrix.python-version }}
install-just: true
- name: Run tests
# env: # Add environment variables required for tests
run: |
just test

lint-dockerfile:
test-package-build:
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

runs-on: ubuntu-latest

env:
PYTHON_VERSION: python${{ matrix.python-version }}

name: Test we can build a Python package
steps:
- uses: actions/checkout@v4
- uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0
with:
failure-threshold: error
fetch-depth: 0
- uses: "opensafely-core/setup-action@v1"
with:
python-version: ${{ matrix.python-version }}
install-just: true

- name: Check the wheel installs and runs
run: just package-test wheel

- name: Check the sdist installs and runs
run: just package-test sdist

tag-new-version:
needs: [check, test, test-package-build]
runs-on: ubuntu-latest

if: github.ref == 'refs/heads/main'

steps:
- uses: actions/checkout@v4
- name: Tag new release
run: |
# ignore failures here to avoid merges into main without version
# bumps failing this job.
git tag "v$(cat version)" || exit
git push --tags

required-checks:
if: always()

needs:
- check
- test

runs-on: Ubuntu-latest

steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
with:
jobs: ${{ toJSON(needs) }}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/.coverage*
/.pytest-cache/
/.venv/
/__pycache__
*/__pycache__
/htmlcov
/dist/
/opentelemetry_opensafely.egg-info/
35 changes: 0 additions & 35 deletions .pre-commit-config.yaml

This file was deleted.

21 changes: 19 additions & 2 deletions DEVELOPERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,31 @@ just # shortcut for just --list

## Local development environment


Set up a local development environment with:
```
just dev_setup
just devenv
```

## Tests
Run the tests with:
```
just test <args>
```

## Building the package

Test that the package builds

```
just package-test whl
just package-test sdist
```

## Create a new release from current main

This pulls `main`, checks out a new release branch, creates and commits a new
`version` file, and opens a PR. Github actions will deal with tagging the new version.

```
just release
```
3 changes: 0 additions & 3 deletions Dockerfile

This file was deleted.

108 changes: 86 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,93 @@
# opentelemetry-opensafely

This is a template for an OpenSAFELY Core repository.

Put your project description here.

New repo checklist:
- [ ] Does the repo require a Dockerfile?
If not, delete:
- Dockerfile -
- .dockerignore
- hadolint pre-commit hook from `.pre-commit-config.yaml`
- `lint-dockerfile` action from `.github/workflows/main.yml`
- [ ] Is this a Django project?
If so, you probably need to add the following per-file ignores to `.flake8`
```
per-file-ignores =
manage.py:INP001
gunicorn.conf.py:INP001
```
- [ ] Will this project be installed with pip?
If so, delete `requirements.prod.in` and switch references in the `justfile` to `pyproject.toml`
- [ ] Update DEVELOPERS.md with any project-specific requirements and commands
- [ ] Update commands in `justfile`
[Opentelemetry](https://opentelemetry.io/) utils for OpenSAFELY.


Provides a function decorator [0] for instrumenting code with
OpenTelemetry traces.


## The @instrument decorator
The decorator allows you to skip much of the boilerplate involved in
setting up tracing spans. OpenTelemetry has a `@start_as_current_span`
decorator, but it doesn't allow adding custom attributes to it.

To use it:

### Basic use

```
from otel_opensafely.trace import instrument

@instrument
def my_function():
...
```
This automatically creates a span named "my_function". By default, the span is named after the function name. To use a custom name, pass a `span_name` argument.

### With named span
```
@instrument(span_name="my_span")
def my_function():
...
```
This creates a span named "my_function".


### With custom attributes

To add custom attributes to the span:

```
@instrument(span_name="my_span", "attributes": {"foo": "bar})
def my_function(foo, *, bar=None):
...
```

### With attributes from the function arguments

Sometimes we might want to add attributes that are based on the
value of a parameter, rather than static values. E.g. in the
function below, we want to add an attribute with the value of "name",
so we can filter traces by name.

```
def say_hello(nm):
print(f"Hello {nm}")
```

To do this, use `func_attributes`; a dict of k:v pairs, where
k is the name of the attribute to add, and v is the name of the parameter:

```
@instrument(func_attributes={"name": "nm"})
def say_hello(nm):
print(f"Hello {nm}")
```

Calling this function with `say_hello("Bob")` will add the attribute
`{"name": "Bob"}` to this span.

`func_attributes` can refer to positional or keyword arguments, e.g.:

```
@instrument(func_attrbutes={"extra": "extra_greeting"})
def say_hello(nm, extra_greeting=None):
print(f"Hello {nm}, {extra_greeting}")
```
Calling this function with `say_hello("Bob", extra_greeting="Howdy!")` will
add the attribute `{"extra": "Howdy!"}` to this span.


### Using an existing tracer
An `existing_tracer` can be passed to the decorator, if one has been
defined already; if not, a tracer is created, named with the `OTEL_SERVICE_NAME`
environment variable, if it exists, or the function module.


## Developer docs

Please see the [additional information](DEVELOPERS.md).


[0] Borrowed heavily from [this post](https://betterprogramming.pub/using-decorators-to-instrument-python-code-with-opentelemetry-traces-d7f1c7d6f632)
Loading
Loading