mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-29 13:12:39 +08:00
Add a rich console exporter (#686)
* Add a rich console exporter * be more lenient on missing parent spans * Apply suggestions from code review Co-authored-by: Aaron Abbott <aaronabbott@google.com> * run black over source * patch change by hand * update changelog * remove defunct statement * Clarify the simple/batch span processor * fix f-strings that dont have formatting * clarify span usage and update classifiers * make child_to_tree a private function and rename some variables Co-authored-by: Aaron Abbott <aaronabbott@google.com> Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com> Co-authored-by: alrex <aboten@lightstep.com>
This commit is contained in:
@ -12,10 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Added
|
### Added
|
||||||
- `opentelemetry-instrumentation-elasticsearch` Added `response_hook` and `request_hook` callbacks
|
- `opentelemetry-instrumentation-elasticsearch` Added `response_hook` and `request_hook` callbacks
|
||||||
([#670](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/670))
|
([#670](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/670))
|
||||||
|
|
||||||
### Added
|
|
||||||
- `opentelemetry-instrumentation-redis` added request_hook and response_hook callbacks passed as arguments to the instrument method.
|
- `opentelemetry-instrumentation-redis` added request_hook and response_hook callbacks passed as arguments to the instrument method.
|
||||||
([#669](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/669))
|
([#669](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/669))
|
||||||
|
- `opentelemetry-exporter-richconsole` Initial release
|
||||||
|
([#686](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/686))
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- `opentelemetry-instrumentation-botocore` Unpatch botocore Endpoint.prepare_request on uninstrument
|
- `opentelemetry-instrumentation-botocore` Unpatch botocore Endpoint.prepare_request on uninstrument
|
||||||
|
28
exporter/opentelemetry-exporter-richconsole/README.rst
Normal file
28
exporter/opentelemetry-exporter-richconsole/README.rst
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
OpenTelemetry Rich Console Exporter
|
||||||
|
===================================
|
||||||
|
|
||||||
|
|pypi|
|
||||||
|
|
||||||
|
.. |pypi| image:: https://badge.fury.io/py/opentelemetry-exporter-richconsole.svg
|
||||||
|
:target: https://pypi.org/project/opentelemetry-exporter-richconsole/
|
||||||
|
|
||||||
|
This library is a console exporter using the Rich tree view. When used with a batch span processor, the rich console exporter will show the trace as a
|
||||||
|
tree and all related spans as children within the tree, including properties.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
pip install opentelemetry-exporter-richconsole
|
||||||
|
|
||||||
|
|
||||||
|
.. _Rich: https://rich.readthedocs.io/
|
||||||
|
.. _OpenTelemetry: https://github.com/open-telemetry/opentelemetry-python/
|
||||||
|
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
|
||||||
|
* `Rich <https://rich.readthedocs.io/>`_
|
||||||
|
* `OpenTelemetry Project <https://opentelemetry.io/>`_
|
51
exporter/opentelemetry-exporter-richconsole/setup.cfg
Normal file
51
exporter/opentelemetry-exporter-richconsole/setup.cfg
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Copyright The OpenTelemetry Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
[metadata]
|
||||||
|
name = opentelemetry-exporter-richconsole
|
||||||
|
description = Rich Console Exporter for OpenTelemetry
|
||||||
|
long_description = file: README.rst
|
||||||
|
long_description_content_type = text/x-rst
|
||||||
|
author = OpenTelemetry Authors
|
||||||
|
author_email = cncf-opentelemetry-contributors@lists.cncf.io
|
||||||
|
url = https://github.com/open-telemetry/opentelemetry-python-contrib/exporter/opentelemetry-exporter-richconsole
|
||||||
|
platforms = any
|
||||||
|
license = Apache-2.0
|
||||||
|
classifiers =
|
||||||
|
Development Status :: 4 - Beta
|
||||||
|
Intended Audience :: Developers
|
||||||
|
License :: OSI Approved :: Apache Software License
|
||||||
|
Programming Language :: Python
|
||||||
|
Programming Language :: Python :: 3
|
||||||
|
Programming Language :: Python :: 3.6
|
||||||
|
Programming Language :: Python :: 3.7
|
||||||
|
Programming Language :: Python :: 3.8
|
||||||
|
Programming Language :: Python :: 3.9
|
||||||
|
|
||||||
|
[options]
|
||||||
|
python_requires = >=3.6
|
||||||
|
package_dir=
|
||||||
|
=src
|
||||||
|
packages=find_namespace:
|
||||||
|
install_requires =
|
||||||
|
rich>=10.0.0
|
||||||
|
opentelemetry-api ~= 1.3
|
||||||
|
opentelemetry-sdk ~= 1.3
|
||||||
|
opentelemetry-semantic-conventions == 0.24b0
|
||||||
|
|
||||||
|
[options.packages.find]
|
||||||
|
where = src
|
||||||
|
|
||||||
|
[options.extras_require]
|
||||||
|
test =
|
27
exporter/opentelemetry-exporter-richconsole/setup.py
Normal file
27
exporter/opentelemetry-exporter-richconsole/setup.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Copyright The OpenTelemetry Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
BASE_DIR = os.path.dirname(__file__)
|
||||||
|
VERSION_FILENAME = os.path.join(
|
||||||
|
BASE_DIR, "src", "opentelemetry", "exporter", "richconsole", "version.py"
|
||||||
|
)
|
||||||
|
PACKAGE_INFO = {}
|
||||||
|
with open(VERSION_FILENAME) as f:
|
||||||
|
exec(f.read(), PACKAGE_INFO)
|
||||||
|
|
||||||
|
setuptools.setup(version=PACKAGE_INFO["__version__"])
|
@ -0,0 +1,173 @@
|
|||||||
|
# Copyright The OpenTelemetry Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""
|
||||||
|
The **OpenTelemetry Rich Console Exporter** provides a span exporter from a batch span processor
|
||||||
|
to print `OpenTelemetry`_ traces using `Rich`_.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
pip install opentelemetry-exporter-richconsole
|
||||||
|
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
The Rich Console Exporter is a console exporter that prints a tree view onto stdout of the traces
|
||||||
|
with the related spans and properties as children of that tree. For the tree view, the Rich
|
||||||
|
Console Exporter should be used with a BatchSpanProcessor. If used within a SimpleSpanProcessor,
|
||||||
|
all spans will be printed in a list.
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
from opentelemetry import trace
|
||||||
|
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
||||||
|
from opentelemetry.exporter.richconsole import RichConsoleExporter
|
||||||
|
from opentelemetry.sdk.trace import TracerProvider
|
||||||
|
|
||||||
|
trace.set_tracer_provider(TracerProvider())
|
||||||
|
tracer = trace.get_tracer(__name__)
|
||||||
|
|
||||||
|
tracer.add_span_processor(BatchSpanProcessor(RichConsoleExporter()))
|
||||||
|
|
||||||
|
|
||||||
|
API
|
||||||
|
---
|
||||||
|
.. _Rich: https://rich.readthedocs.io/
|
||||||
|
.. _OpenTelemetry: https://github.com/open-telemetry/opentelemetry-python/
|
||||||
|
"""
|
||||||
|
# pylint: disable=import-error
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import typing
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from rich.console import Console
|
||||||
|
from rich.syntax import Syntax
|
||||||
|
from rich.text import Text
|
||||||
|
from rich.tree import Tree
|
||||||
|
|
||||||
|
import opentelemetry.trace
|
||||||
|
from opentelemetry.sdk.trace import ReadableSpan
|
||||||
|
from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
|
||||||
|
from opentelemetry.semconv.trace import SpanAttributes
|
||||||
|
|
||||||
|
|
||||||
|
def _ns_to_time(nanoseconds):
|
||||||
|
ts = datetime.datetime.utcfromtimestamp(nanoseconds / 1e9)
|
||||||
|
return ts.strftime("%H:%M:%S.%f")
|
||||||
|
|
||||||
|
|
||||||
|
def _child_to_tree(child: Tree, span: ReadableSpan):
|
||||||
|
child.add(
|
||||||
|
Text.from_markup(f"[bold cyan]Kind :[/bold cyan] {span.kind.name}")
|
||||||
|
)
|
||||||
|
if not span.status.is_unset:
|
||||||
|
if not span.status.is_ok:
|
||||||
|
child.add(
|
||||||
|
Text.from_markup(
|
||||||
|
f"[bold cyan]Status :[/bold cyan] [red]{span.status.status_code}[/red]"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
child.add(
|
||||||
|
Text.from_markup(
|
||||||
|
f"[bold cyan]Status :[/bold cyan] {span.status.status_code}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if span.status.description:
|
||||||
|
child.add(
|
||||||
|
Text.from_markup(
|
||||||
|
f"[bold cyan]Description :[/bold cyan] {span.status.description}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if span.events:
|
||||||
|
events = child.add(
|
||||||
|
label=Text.from_markup("[bold cyan]Events :[/bold cyan] ")
|
||||||
|
)
|
||||||
|
for event in span.events:
|
||||||
|
event_node = events.add(Text(event.name))
|
||||||
|
for key, val in event.attributes.items():
|
||||||
|
event_node.add(
|
||||||
|
Text.from_markup(f"[bold cyan]{key} :[/bold cyan] {val}")
|
||||||
|
)
|
||||||
|
if span.attributes:
|
||||||
|
attributes = child.add(
|
||||||
|
label=Text.from_markup("[bold cyan]Attributes :[/bold cyan] ")
|
||||||
|
)
|
||||||
|
for attribute in span.attributes:
|
||||||
|
if attribute == SpanAttributes.DB_STATEMENT:
|
||||||
|
attributes.add(
|
||||||
|
Text.from_markup(f"[bold cyan]{attribute} :[/bold cyan] ")
|
||||||
|
)
|
||||||
|
attributes.add(Syntax(span.attributes[attribute], "sql"))
|
||||||
|
else:
|
||||||
|
attributes.add(
|
||||||
|
Text.from_markup(
|
||||||
|
f"[bold cyan]{attribute} :[/bold cyan] {span.attributes[attribute]}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RichConsoleSpanExporter(SpanExporter):
|
||||||
|
"""Implementation of :class:`SpanExporter` that prints spans to the
|
||||||
|
console.
|
||||||
|
|
||||||
|
Should be used within a BatchSpanProcessor
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, service_name: Optional[str] = None,
|
||||||
|
):
|
||||||
|
self.service_name = service_name
|
||||||
|
self.console = Console()
|
||||||
|
|
||||||
|
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 not in parents:
|
||||||
|
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)}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
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)
|
||||||
|
|
||||||
|
self.console.print(tree)
|
||||||
|
return SpanExportResult.SUCCESS
|
@ -0,0 +1,15 @@
|
|||||||
|
# Copyright The OpenTelemetry Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
__version__ = "0.24b0"
|
Reference in New Issue
Block a user