Skip to content

Commit

Permalink
Merge branch 'main' into aws_ecs_detector
Browse files Browse the repository at this point in the history
  • Loading branch information
Michele Mancioppi committed Oct 13, 2022
2 parents bc751ea + 744851b commit 09b66c5
Show file tree
Hide file tree
Showing 10 changed files with 583 additions and 53 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Expand Up @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.13.0-0.34b0...HEAD)
- Add metric instrumentation for tornado
([#1252](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1252))


### Added

Expand All @@ -14,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `opentelemetry-instrumentation-system-metrics` add supports to collect system thread count. ([#1339](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1339))
- Implement [`aws.ecs.*`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/cloud_provider/aws/ecs.md) and [`aws.logs.*`](https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/cloud_provider/aws/logs/) resource attributes in the `AwsEcsResourceDetector` detector when the ECS Metadata v4 is available
([#1212](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1212))
- `opentelemetry-exporter-richconsole` Fixing RichConsoleExpoter to allow multiple traces, fixing duplicate spans and include resources ([#1336](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1336))

## [1.13.0-0.34b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.13.0-0.34b0) - 2022-09-26

Expand Down Expand Up @@ -75,6 +79,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#1197](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1197))
- Add metric instumentation for flask
([#1186](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1186))
- Add a test for asgi using NoOpTracerProvider
([#1367](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1367))

## [1.12.0rc2-0.32b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.12.0rc2-0.32b0) - 2022-07-01

Expand Down
Expand Up @@ -54,7 +54,7 @@

import datetime
import typing
from typing import Optional
from typing import Dict, Optional

from rich.console import Console
from rich.syntax import Syntax
Expand All @@ -76,6 +76,11 @@ def _child_to_tree(child: Tree, span: ReadableSpan):
child.add(
Text.from_markup(f"[bold cyan]Kind :[/bold cyan] {span.kind.name}")
)
_add_status(child, span)
_child_add_optional_attributes(child, span)


def _add_status(child: Tree, span: ReadableSpan):
if not span.status.is_unset:
if not span.status.is_ok:
child.add(
Expand All @@ -96,6 +101,8 @@ def _child_to_tree(child: Tree, span: ReadableSpan):
)
)


def _child_add_optional_attributes(child: Tree, span: ReadableSpan):
if span.events:
events = child.add(
label=Text.from_markup("[bold cyan]Events :[/bold cyan] ")
Expand All @@ -122,6 +129,16 @@ def _child_to_tree(child: Tree, span: ReadableSpan):
f"[bold cyan]{attribute} :[/bold cyan] {span.attributes[attribute]}"
)
)
if span.resource:
resources = child.add(
label=Text.from_markup("[bold cyan]Resources :[/bold cyan] ")
)
for resource in span.resource.attributes:
resources.add(
Text.from_markup(
f"[bold cyan]{resource} :[/bold cyan] {span.resource.attributes[resource]}"
)
)


class RichConsoleSpanExporter(SpanExporter):
Expand All @@ -141,35 +158,39 @@ def __init__(
def export(self, spans: typing.Sequence[ReadableSpan]) -> SpanExportResult:
if not spans:
return SpanExportResult.SUCCESS
tree = Tree(
label=f"Trace {opentelemetry.trace.format_trace_id(spans[0].context.trace_id)}"
)
parents = {}
for span in spans:
child = tree.add(
label=Text.from_markup(
f"[blue][{_ns_to_time(span.start_time)}][/blue] [bold]{span.name}[/bold], span {opentelemetry.trace.format_span_id(span.context.span_id)}"
)
)
parents[span.context.span_id] = child
_child_to_tree(child, span)

for span in spans:
if span.parent and span.parent.span_id in parents:
child = parents[span.parent.span_id].add(
label=Text.from_markup(
f"[blue][{_ns_to_time(span.start_time)}][/blue] [bold]{span.name}[/bold], span {opentelemetry.trace.format_span_id(span.context.span_id)}"
)
)
else:
child = tree.add(
label=Text.from_markup(
f"[blue][{_ns_to_time(span.start_time)}][/blue] [bold]{span.name}[/bold], span {opentelemetry.trace.format_span_id(span.context.span_id)}"
)
)

parents[span.context.span_id] = child
_child_to_tree(child, span)
for tree in self.spans_to_tree(spans).values():
self.console.print(tree)

self.console.print(tree)
return SpanExportResult.SUCCESS

@staticmethod
def spans_to_tree(spans: typing.Sequence[ReadableSpan]) -> Dict[str, Tree]:
trees = {}
parents = {}
spans = list(spans)
while spans:
for span in spans:
if not span.parent:
trace_id = opentelemetry.trace.format_trace_id(
span.context.trace_id
)
trees[trace_id] = Tree(label=f"Trace {trace_id}")
child = trees[trace_id].add(
label=Text.from_markup(
f"[blue][{_ns_to_time(span.start_time)}][/blue] [bold]{span.name}[/bold], span {opentelemetry.trace.format_span_id(span.context.span_id)}"
)
)
parents[span.context.span_id] = child
_child_to_tree(child, span)
spans.remove(span)
elif span.parent and span.parent.span_id in parents:
child = parents[span.parent.span_id].add(
label=Text.from_markup(
f"[blue][{_ns_to_time(span.start_time)}][/blue] [bold]{span.name}[/bold], span {opentelemetry.trace.format_span_id(span.context.span_id)}"
)
)
parents[span.context.span_id] = child
_child_to_tree(child, span)
spans.remove(span)
return trees
Expand Up @@ -13,7 +13,9 @@
# limitations under the License.

import pytest
from rich.tree import Tree

import opentelemetry.trace
from opentelemetry.exporter.richconsole import RichConsoleSpanExporter
from opentelemetry.sdk import trace
from opentelemetry.sdk.trace.export import BatchSpanProcessor
Expand All @@ -40,8 +42,57 @@ def fixture_tracer_provider(span_processor):
def test_span_exporter(tracer_provider, span_processor, capsys):
tracer = tracer_provider.get_tracer(__name__)
span = tracer.start_span("test_span")

span.set_attribute("key", "V4LuE")
span.end()
span_processor.force_flush()
captured = capsys.readouterr()

assert "V4LuE" in captured.out


def walk_tree(root: Tree) -> int:
# counts the amount of spans in a tree that contains a span
return sum(walk_tree(child) for child in root.children) + int(
"span" in root.label
)


def test_multiple_traces(tracer_provider):
exporter = RichConsoleSpanExporter()
tracer = tracer_provider.get_tracer(__name__)
with tracer.start_as_current_span("parent_1") as parent_1:
with tracer.start_as_current_span("child_1") as child_1:
pass

with tracer.start_as_current_span("parent_2") as parent_2:
pass

trees = exporter.spans_to_tree((parent_2, parent_1, child_1))
# asserts that we have all traces
assert len(trees) == 2
traceid_1 = opentelemetry.trace.format_trace_id(parent_1.context.trace_id)

assert traceid_1 in trees

assert (
opentelemetry.trace.format_trace_id(parent_2.context.trace_id) in trees
)

# asserts that we have exactly the number of spans we exported
assert sum(walk_tree(tree) for tree in trees.values()) == 3

# assert that the relationship is correct
assert parent_1.name in trees[traceid_1].children[0].label
assert any(
child_1.name in child.label
for child in trees[traceid_1].children[0].children
)
assert not any(
parent_1.name in child.label
for child in trees[traceid_1].children[0].children
)
assert not any(
parent_2.name in child.label
for child in trees[traceid_1].children[0].children
)
2 changes: 1 addition & 1 deletion instrumentation/README.md
Expand Up @@ -38,7 +38,7 @@
| [opentelemetry-instrumentation-sqlite3](./opentelemetry-instrumentation-sqlite3) | sqlite3 | No
| [opentelemetry-instrumentation-starlette](./opentelemetry-instrumentation-starlette) | starlette ~= 0.13.0 | Yes
| [opentelemetry-instrumentation-system-metrics](./opentelemetry-instrumentation-system-metrics) | psutil >= 5 | No
| [opentelemetry-instrumentation-tornado](./opentelemetry-instrumentation-tornado) | tornado >= 5.1.1 | No
| [opentelemetry-instrumentation-tornado](./opentelemetry-instrumentation-tornado) | tornado >= 5.1.1 | Yes
| [opentelemetry-instrumentation-urllib](./opentelemetry-instrumentation-urllib) | urllib | No
| [opentelemetry-instrumentation-urllib3](./opentelemetry-instrumentation-urllib3) | urllib3 >= 1.0.0, < 2.0.0 | Yes
| [opentelemetry-instrumentation-wsgi](./opentelemetry-instrumentation-wsgi) | wsgi | Yes
Expand Up @@ -300,6 +300,20 @@ def test_custom_tracer_provider_otel_asgi(self):
span.resource.attributes["service-test-key"], "value"
)

def test_no_op_tracer_provider_otel_asgi(self):
app = otel_asgi.OpenTelemetryMiddleware(
simple_asgi, tracer_provider=trace_api.NoOpTracerProvider()
)
self.seed_app(app)
self.send_default_request()

response_start, response_body, *_ = self.get_all_output()
self.assertEqual(response_body["body"], b"*")
self.assertEqual(response_start["status"], 200)

span_list = self.memory_exporter.get_finished_spans()
self.assertEqual(len(span_list), 0)

def test_behavior_with_scope_server_as_none(self):
"""Test that middleware is ok when server is none in scope."""

Expand Down

0 comments on commit 09b66c5

Please sign in to comment.