Skip to content

Commit

Permalink
merge with master
Browse files Browse the repository at this point in the history
  • Loading branch information
Eugene Orlovsky committed Dec 4, 2024
2 parents d91ea11 + 34e4bb1 commit 4c947f3
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 1 deletion.
47 changes: 46 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ The [no-code activation](#no-code-activation) approach is the preferred one.

Set the following environment variable:

```console
```sh
AUTOWRAPT_BOOTSTRAP=lumigo_opentelemetry
```

Expand All @@ -82,6 +82,24 @@ Import `lumigo_opentelemetry` at the beginning of your main file:
import lumigo_opentelemetry
```

#### Script instrumentation

For simple Python scripts that are not built around Lumigo or OpenTelemetry-instrumented libraries, you can use the `@lumigo_wrapped` decorator for activation. This approach is especially useful for standalone scripts, cron jobs, or similar use cases.

Import the `lumigo_wrapped` decorator and wrap your functions to automatically create OpenTelemetry spans:

```python
from lumigo_opentelemetry import lumigo_wrapped

@lumigo_wrapped
def your_function():
pass
```

See the [Using the `@lumigo_wrapped` Decorator](#using-the-lumigo_wrapped-decorator) section for more details.

**Note:** If no outbound requests are made (e.g., the code crashes before the first call is executed), the script run will not generate any traces in Lumigo. This limitation is inherent to the OpenTelemetry behavior and the need for spans to be triggered by instrumentation or custom tracing calls.

## Configuration

### OpenTelemetry configurations
Expand Down Expand Up @@ -224,6 +242,33 @@ from opentelemetry.trace import get_current_span
get_current_span().add_event('<error-message>', {'lumigo.type': '<error-type>'})
```

### Using the `@lumigo_wrapped` Decorator

The `@lumigo_wrapped` decorator is a convenient way to add Lumigo tracing to functions in scripts that are not using libraries or frameworks instrumented by Lumigo or OpenTelemetry.

When applied, the decorator creates an OpenTelemetry span for the decorated function, adding attributes such as:

- `input_args`: The positional arguments passed to the function.
- `input_kwargs`: The keyword arguments passed to the function.
- `return_value`: The value returned by the function.

Here's a simple example using the `@lumigo_wrapped` decorator:

```python
from lumigo_opentelemetry import lumigo_wrapped

@lumigo_wrapped
def calculate_sum(start, end):
"""Calculates the sum of numbers in a given range."""
return sum(range(start, end + 1))

if __name__ == "__main__":
result = calculate_sum(1, 100)
print(f"The sum of numbers from 1 to 100 is: {result}")

```
In the example above, a span will be created automatically when calculate_sum() is called, capturing the function arguments (start and end) and the return value (the calculated sum) as span attributes.

## Python 3.7 Support

**Deprecation Notice:** As of version 1.0.156, support for Python 3.7 has been deprecated. The last version of the Lumigo OpenTelemetry Distro to support Python 3.7 is version 1.0.155.
Expand Down
42 changes: 42 additions & 0 deletions src/test/unit/test_tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,45 @@ def test_create_event_with_correct_attributes(self):
# Verify the event has the correct attributes
self.assertEqual(event.name, "Error message")
self.assertEqual(event.attributes["lumigo.type"], "ErrorType")


class TestLumigoWrapped(unittest.TestCase):
@httpretty.activate(allow_net_connect=False)
def test_access_lumigo_wrapped(self):
from lumigo_opentelemetry import lumigo_wrapped, tracer_provider

self.assertIsNotNone(lumigo_wrapped)
self.assertIsNotNone(tracer_provider)

span_processor = Mock(SpanProcessor)
tracer_provider.add_span_processor(span_processor)

@lumigo_wrapped
def sample_function(x, y):
return x + y

result = sample_function(1, 2)

self.assertEqual(result, 3)

# Assert `on_start` was called at least once
span_processor.on_start.assert_called()

# Verify `on_start` was called
span_processor.on_start.assert_called()

# Capture the span passed to `on_start`
span = span_processor.on_start.call_args[0][
0
] # Extract the `span` argument from the first call

# Assess attributes of the span
self.assertEqual(
span.attributes["input_args"], "[1, 2]"
) # Check serialized input args
self.assertEqual(
span.attributes["input_kwargs"], "{}"
) # Check serialized input kwargs
self.assertEqual(
span.attributes["return_value"], "3"
) # Check serialized return value

0 comments on commit 4c947f3

Please sign in to comment.