<commit_before># Lesson 1 - Hello World

## Objectives

Learn how to:

* Instantiate a Tracer
* Create a simple trace
* Annotate the trace

## Walkthrough

### A simple Hello-World program

Let's create a simple Python program `lesson01/exercise/hello.py` that takes an argument and prints "Hello, {arg}!".

```
mkdir lesson01/exercise
touch lesson01/exercise/__init__.py
```

```python
# lesson01/exercise/hello.py
import sys

def say_hello(hello_to):
    hello_str = 'Hello, %s!' % hello_to
    print(hello_str)

assert len(sys.argv) == 2

hello_to = sys.argv[1]
say_hello(hello_to)
```

Run it:
```
$ python -m lesson01.exercise.hello Bryan
Hello, Bryan!
```

### Create a trace

A trace is a directed acyclic graph of spans. A span is a logical representation of some work done in your application.
Each span has these minimum attributes: an operation name, a start time, and a finish time.

Let's create a trace that consists of just a single span. To do that we need an instance of the `opentracing.Tracer`.
We can use a global instance stored in `opentracing.tracer`.

```python
import opentracing

tracer = opentracing.tracer

def say_hello(hello_to):
    span = tracer.start_span('say-hello')
    hello_str = 'Hello, %s!' % hello_to
    print(hello_str)
    span.finish()
```

We are using the following basic features of the OpenTracing API:
  * a `tracer` instance is used to start new spans via `start_span` function
  * each `span` is given an _operation name_, `'say-hello'` in this case
  * each `span` must be finished by calling its `finish()` function
  * the start and end timestamps of the span will be captured automatically by the tracer implementation

However, calling `finish()` manually is a bit tedious, we can use span as a context manager instead:

```python
def say_hello(hello_to):
    with tracer.start_span('say-hello') as span:
        hello_str = 'Hello, %s!' % hello_to
        print(hello_str)
```

If we run this program, we will see no difference, and no traces in the tracing UI.
That's because the variable `opentracing.tracer` points to a no-op tracer by default.

### Initialize a real tracer

Let's create an instance of a real tracer, such as Jaeger (http://github.com/uber/jaeger-client-python).

```python
import logging
from jaeger_client import Config


def init_tracer(service):
    logging.getLogger('').handlers = []
    logging.basicConfig(format='%(message)s', level=logging.DEBUG)

    config = Config(
        config={
            'sampler': {
                'type': 'const',
                'param': 1,
            },
            'logging': True,
        },
        service_name=service,
    )

    # this call also sets opentracing.tracer
    return config.initialize_tracer()
```

To use this instance, let's replace `opentracing.tracer` with `init_tracer(...)`:

```python
tracer = init_tracer('hello-world')
```

Note that we are passing a string `'hello-world'` to the init method. It is used to mark all spans emitted by
the tracer as originating from a `hello-world` service.

There's one more thing we need to do. Jaeger Tracer is primarily designed for long-running server processes,
so it has an internal buffer of spans that is flushed by a background thread. Since our program exists immediately,
it may not have time to flush the spans to Jaeger backend. Let's add the following to the end of `hello.py`:

```
import time

# ...

# yield to IOLoop to flush the spans
time.sleep(2)
tracer.close()
```<commit_msg>python | lesson01 - Fix readme.md (#55)<commit_after># Lesson 1 - Hello World

## Objectives

Learn how to:

* Instantiate a Tracer
* Create a simple trace
* Annotate the trace

## Walkthrough

### A simple Hello-World program

Let's create a simple Python program `lesson01/exercise/hello.py` that takes an argument and prints "Hello, {arg}!".

```
mkdir lesson01/exercise
touch lesson01/exercise/__init__.py
```

```python
# lesson01/exercise/hello.py
import sys

def say_hello(hello_to):
    hello_str = 'Hello, %s!' % hello_to
    print(hello_str)

assert len(sys.argv) == 2

hello_to = sys.argv[1]
say_hello(hello_to)
```

Run it:
```
$ python -m lesson01.exercise.hello Bryan
Hello, Bryan!
```

### Create a trace

A trace is a directed acyclic graph of spans. A span is a logical representation of some work done in your application.
Each span has these minimum attributes: an operation name, a start time, and a finish time.

Let's create a trace that consists of just a single span. To do that we need an instance of the `opentracing.Tracer`.
We can use a global instance stored in `opentracing.tracer`.

```python
import opentracing

tracer = opentracing.tracer

def say_hello(hello_to):
    span = tracer.start_span('say-hello')
    hello_str = 'Hello, %s!' % hello_to
    print(hello_str)
    span.finish()
```

We are using the following basic features of the OpenTracing API:
  * a `tracer` instance is used to start new spans via `start_span` function
  * each `span` is given an _operation name_, `'say-hello'` in this case
  * each `span` must be finished by calling its `finish()` function
  * the start and end timestamps of the span will be captured automatically by the tracer implementation

However, calling `finish()` manually is a bit tedious, we can use span as a context manager instead:

```python
def say_hello(hello_to):
    with tracer.start_span('say-hello') as span:
        hello_str = 'Hello, %s!' % hello_to
        print(hello_str)
```

If we run this program, we will see no difference, and no traces in the tracing UI.
That's because the variable `opentracing.tracer` points to a no-op tracer by default.

### Initialize a real tracer

Let's create an instance of a real tracer, such as Jaeger (http://github.com/uber/jaeger-client-python).

```python
import logging
from jaeger_client import Config


def init_tracer(service):
    logging.getLogger('').handlers = []
    logging.basicConfig(format='%(message)s', level=logging.DEBUG)

    config = Config(
        config={
            'sampler': {
                'type': 'const',
                'param': 1,
            },
            'logging': True,
        },
        service_name=service,
    )

    # this call also sets opentracing.tracer
    return config.initialize_tracer()
```

To use this instance, let's replace `opentracing.tracer` with `init_tracer(...)`:

```python
tracer = init_tracer('hello-world')
```

Note that we are passing a string `'hello-world'` to the init method. It is used to mark all spans emitted by
the tracer as originating from a `hello-world` service.

There's one more thing we need to do. Jaeger Tracer is primarily designed for long-running server processes,
so it has an internal buffer of spans that is flushed by a background thread. Since our program exits immediately,
it may not have time to flush the spans to Jaeger backend. Let's add the following to the end of `hello.py`:

```
import time

# ...

# yield to IOLoop to flush the spans
time.sleep(2)
tracer.close()
```
{'fraction_non_alphanumeric': 0.09901273429675204, 'fraction_numerical': 0.004864787523250823, 'mean_word_length': 3.6383543463835433, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1042905', 'n_tokens_mistral': 2211, 'n_tokens_neox': 2061, 'n_words': 860}