Migrate otel_telemetry to contrib (#43)
This commit is contained in:
parent
8755d5fdba
commit
d7eb7b8a24
|
@ -11,6 +11,9 @@ elixir:
|
|||
- examples/**/*.ex
|
||||
- examples/**/*.exs
|
||||
- examples/**/mix.lock
|
||||
- utilities/**/*.ex
|
||||
- utilities/**/*.exs
|
||||
- utilities/**/mix.lock
|
||||
|
||||
erlang:
|
||||
- instrumentation/**/*.erl
|
||||
|
@ -25,6 +28,9 @@ erlang:
|
|||
- examples/**/*.erl
|
||||
- examples/**/*.hrl
|
||||
- examples/**/rebar.*
|
||||
- utilities/**/*.erl
|
||||
- utilities/**/*.hrl
|
||||
- utilities/**/rebar.*
|
||||
|
||||
instrumentation:
|
||||
- instrumentation/**/*
|
||||
|
@ -35,6 +41,9 @@ propagators:
|
|||
examples:
|
||||
- examples/**/*
|
||||
|
||||
utilities:
|
||||
- utilities/**/*
|
||||
|
||||
scope-ci:
|
||||
- .github/workflows/**
|
||||
|
||||
|
@ -46,3 +55,6 @@ opentelemetry_ecto:
|
|||
|
||||
opentelemetry_phoenix:
|
||||
- instrumentation/opentelemetry_phoenix/**/*
|
||||
|
||||
opentelemetry_telemetry:
|
||||
- utilities/opentelemetry_telemetry/**/*
|
||||
|
|
|
@ -104,3 +104,40 @@ jobs:
|
|||
run: mix format --check-formatted
|
||||
- name: Test
|
||||
run: mix test
|
||||
|
||||
opentelemetry-telemetry:
|
||||
needs: [test-matrix]
|
||||
if: (contains(github.event.pull_request.labels.*.name, 'elixir') && contains(github.event.pull_request.labels.*.name, 'opentelemetry_telemetry'))
|
||||
env:
|
||||
app: 'opentelemetry_telemetry'
|
||||
defaults:
|
||||
run:
|
||||
working-directory: utilities/${{ env.app }}
|
||||
runs-on: ubuntu-18.04
|
||||
name: Opentelemetry Telemetry test on Elixir ${{ matrix.elixir_version }} (OTP ${{ matrix.otp_version }})
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.test-matrix.outputs.matrix) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: erlef/setup-beam@v1
|
||||
with:
|
||||
otp-version: ${{ matrix.otp_version }}
|
||||
elixir-version: ${{ matrix.elixir_version }}
|
||||
rebar3-version: ${{ matrix.rebar3_version }}
|
||||
- name: Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
utilities/${{ env.app }}/deps
|
||||
utilities/${{ env.app }}/_build
|
||||
key: ${{ runner.os }}-build-${{ matrix.otp_version }}-${{ matrix.elixir_version }}-v3-${{ hashFiles(format('{0}{1}', github.workspace, 'utilities/${{ env.app }}/mix.lock')) }}
|
||||
- name: Fetch deps
|
||||
if: steps.deps-cache.outputs.cache-hit != 'true'
|
||||
run: mix deps.get
|
||||
- name: Compile project
|
||||
run: mix compile --warnings-as-errors
|
||||
- name: Check formatting
|
||||
run: mix format --check-formatted
|
||||
- name: Test
|
||||
run: mix test
|
||||
|
|
|
@ -51,3 +51,34 @@ jobs:
|
|||
run: rebar3 get-deps
|
||||
- name: Test
|
||||
run: rebar3 ct
|
||||
|
||||
opentelemetry-telemetry:
|
||||
needs: [test-matrix]
|
||||
if: (contains(github.event.pull_request.labels.*.name, 'erlang') && contains(github.event.pull_request.labels.*.name, 'opentelemetry_telemetry'))
|
||||
env:
|
||||
app: 'opentelemetry_telemetry'
|
||||
defaults:
|
||||
run:
|
||||
working-directory: utilities/${{ env.app }}
|
||||
runs-on: ubuntu-18.04
|
||||
name: Opentelemetry Telemetry test on OTP ${{ matrix.otp_version }} with Rebar3 ${{ matrix.rebar3_version }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.test-matrix.outputs.matrix) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: erlef/setup-beam@v1
|
||||
with:
|
||||
otp-version: ${{ matrix.otp_version }}
|
||||
rebar3-version: ${{ matrix.rebar3_version }}
|
||||
- name: Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
${{ env.app }}/_build
|
||||
key: ${{ runner.os }}-build-${{ matrix.otp_version }}-${{ matrix.rebar3_version }}-v3-${{ hashFiles(format('{0}{1}', github.workspace, 'utilities/${{ env.app }}/rebar.lock')) }}
|
||||
- name: Fetch deps
|
||||
if: steps.deps-cache.outputs.cache-hit != 'true'
|
||||
run: rebar3 get-deps
|
||||
- name: Test
|
||||
run: rebar3 ct
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
@open-telemetry/erlang-approvers
|
||||
|
||||
/instrumentation/opentelemetry_cowboy @bryannaegele @tsloughter
|
||||
/instrumentation/opentelemetry_cowboy @bryannaegele @tsloughter
|
||||
/instrumentation/opentelemetry_ecto @bryannaegele @tsloughter
|
||||
/instrumentation/opentelemetry_phoenix @bryannaegele @tsloughter
|
||||
/utilities/opentelemetry_telemetry @bryannaegele @tsloughter
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
|
@ -0,0 +1,32 @@
|
|||
edoc
|
||||
.rebar3
|
||||
_*
|
||||
.eunit
|
||||
*.o
|
||||
*.beam
|
||||
*.plt
|
||||
*.swp
|
||||
*.swo
|
||||
.erlang.cookie
|
||||
ebin
|
||||
log
|
||||
erl_crash.dump
|
||||
.rebar
|
||||
logs
|
||||
_build
|
||||
.idea
|
||||
*.iml
|
||||
rebar3.crashdump
|
||||
*~
|
||||
!_checkouts
|
||||
|
||||
/_build
|
||||
/cover
|
||||
/deps
|
||||
/doc
|
||||
/.fetch
|
||||
erl_crash.dump
|
||||
*.ez
|
||||
*.beam
|
||||
/config/*.secret.exs
|
||||
.elixir_ls/
|
|
@ -0,0 +1,19 @@
|
|||
# Changelog
|
||||
|
||||
## 1.0.0-beta.4
|
||||
|
||||
### Changes
|
||||
|
||||
* OpenTelemetry 1.0.0-rc.3 support
|
||||
|
||||
## 1.0.0-beta.3
|
||||
|
||||
### Changes
|
||||
|
||||
* telemetry v1.0.0 required
|
||||
|
||||
## 1.0.0-beta.2
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The internal ctx handling mechanisms have been removed from the public API and replaced with more meaningful span operation functions to provide better abstractions
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
|
@ -0,0 +1,45 @@
|
|||
# OpentelemetryTelemetry
|
||||
|
||||
A utility library for creating OpenTelemery spans from telemetry events.
|
||||
|
||||
## Purpose
|
||||
|
||||
Most libraries in the BEAM ecosystem leverage [telemetry](https://github.com/beam-telemetry/telemetry) events for exposing
|
||||
event hook points for monitoring that library. While OpenTelemetry is a great project,
|
||||
it is still one specification for monitoring software and it isn't
|
||||
reasonable to ask library authors to support multiple conventions.
|
||||
|
||||
OpentelemetryTelemetry provides mechanisms for otel instrumentation libraries
|
||||
to leverage telemetry events for creating and managing spans. The instrumentation library
|
||||
is then able to leverage the telemetry measurements and metadata for deriving
|
||||
spans, adding attributes, set span names, etc.
|
||||
|
||||
### What Opentelemetry is Not
|
||||
|
||||
This library is only intended to provide utilities for working with telemetry
|
||||
events to instrumentation libraries. As such, it should not be used directly
|
||||
within your application code where the OpenTelemery API library should be leveraged.
|
||||
|
||||
## Installation
|
||||
|
||||
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
|
||||
by adding `opentelemetry_telemetry` to your list of dependencies:
|
||||
|
||||
```erlang
|
||||
{deps, [
|
||||
{opentelemetry_telemetry, "~> 1.0.0-beta.5"}
|
||||
]}.
|
||||
```
|
||||
|
||||
```elixir
|
||||
def deps do
|
||||
[
|
||||
{:opentelemetry_telemetry, "~> 1.0.0-beta.5"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
||||
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
|
||||
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
|
||||
be found at [https://hexdocs.pm/opentelemetry_telemetry](https://hexdocs.pm/opentelemetry_telemetry).
|
||||
|
|
@ -0,0 +1 @@
|
|||
1.0.0-beta.5
|
|
@ -0,0 +1,20 @@
|
|||
.rebar3
|
||||
_*
|
||||
.eunit
|
||||
*.o
|
||||
*.beam
|
||||
*.plt
|
||||
*.swp
|
||||
*.swo
|
||||
.erlang.cookie
|
||||
ebin
|
||||
log
|
||||
erl_crash.dump
|
||||
.rebar
|
||||
logs
|
||||
_build
|
||||
.idea
|
||||
*.iml
|
||||
rebar3.crashdump
|
||||
*~
|
||||
!_checkouts
|
|
@ -0,0 +1,191 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2020, Bryan Naegele <bryan@fourthtime.com>.
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
test_app
|
||||
=====
|
||||
|
||||
An OTP application
|
||||
|
||||
Build
|
||||
-----
|
||||
|
||||
$ rebar3 compile
|
|
@ -0,0 +1,33 @@
|
|||
{erl_opts, [debug_info]}.
|
||||
{deps, [
|
||||
{test_child_app, "~> 0.1"}
|
||||
]}.
|
||||
|
||||
{profiles, [
|
||||
{test, [{erl_opts, [nowarn_export_all]},
|
||||
{deps, [
|
||||
{test_child_app, "~> 0.1"},
|
||||
{telemetry, "~> 1.0"}
|
||||
]},
|
||||
%% create junit xml for circleci
|
||||
{ct_opts, [{ct_hooks, [cth_surefire]}]},
|
||||
{cover_enabled, true},
|
||||
{cover_opts, [verbose]},
|
||||
{paths, ["src", "test/support"]},
|
||||
%% convert to data codecov understands
|
||||
{plugins, [covertool]},
|
||||
{covertool, [{coverdata_files, ["ct.coverdata"]}]}
|
||||
]},
|
||||
{docs, [{edoc_opts, [{preprocess, true},
|
||||
{title, "Test App"}]}
|
||||
]}
|
||||
]}.
|
||||
|
||||
{shell, [
|
||||
% {config, "config/sys.config"},
|
||||
{apps, [test_app]}
|
||||
]}.
|
||||
|
||||
%% take out warnings for unused exported functions
|
||||
{xref_checks,[undefined_function_calls, undefined_functions, locals_not_used,
|
||||
deprecated_function_calls, deprecated_functions]}.
|
|
@ -0,0 +1 @@
|
|||
[].
|
|
@ -0,0 +1,16 @@
|
|||
{application, test_app,
|
||||
[{description, "An OTP application"},
|
||||
{vsn, "0.1.0"},
|
||||
{registered, []},
|
||||
{mod, {test_app_app, []}},
|
||||
{applications,
|
||||
[kernel,
|
||||
stdlib,
|
||||
test_child_app
|
||||
]},
|
||||
{env,[]},
|
||||
{modules, []},
|
||||
|
||||
{licenses, ["Apache 2.0"]},
|
||||
{links, []}
|
||||
]}.
|
|
@ -0,0 +1,82 @@
|
|||
-module(test_app).
|
||||
|
||||
-export([handler/1]).
|
||||
|
||||
-telemetry_event #{
|
||||
event => [test_app, handler, start],
|
||||
description => <<"Emitted at the start of the handler">>,
|
||||
measurements => <<"#{system_time => non_neg_integer()}">>,
|
||||
metadata => <<"#{}">>
|
||||
}.
|
||||
-telemetry_event #{
|
||||
event => [test_app, handler, stop],
|
||||
description => <<"Emitted at the end of the handler">>,
|
||||
measurements => <<"#{duration => non_neg_integer()}">>,
|
||||
metadata => <<"#{}">>
|
||||
}.
|
||||
-telemetry_event #{
|
||||
event => [test_app, handler, exception],
|
||||
description => <<"The handler raised an exception">>,
|
||||
measurements => <<"#{duration => non_neg_integer()}">>,
|
||||
metadata => <<"#{kind => atom(), reason => atom(), stacktrace => term()}">>
|
||||
}.
|
||||
|
||||
-telemetry_event #{
|
||||
event => [test_app, nested_span, start],
|
||||
description => <<"Emitted at the start of the handler">>,
|
||||
measurements => <<"#{system_time => non_neg_integer()}">>,
|
||||
metadata => <<"#{}">>
|
||||
}.
|
||||
-telemetry_event #{
|
||||
event => [test_app, nested_span, stop],
|
||||
description => <<"Emitted at the end of the handler">>,
|
||||
measurements => <<"#{duration => non_neg_integer()}">>,
|
||||
metadata => <<"#{}">>
|
||||
}.
|
||||
-telemetry_event #{
|
||||
event => [test_app, nested_span, exception],
|
||||
description => <<"The handler raised an exception">>,
|
||||
measurements => <<"#{duration => non_neg_integer()}">>,
|
||||
metadata => <<"#{kind => atom(), reason => atom(), stacktrace => term()}">>
|
||||
}.
|
||||
|
||||
|
||||
-telemetry_event #{
|
||||
event => [test_app, only, stop],
|
||||
description => <<"The handler raised an exception">>,
|
||||
measurements => <<"#{duration => non_neg_integer()}">>,
|
||||
metadata => <<"#{kind => atom(), reason => atom(), stacktrace => term()}">>
|
||||
}.
|
||||
|
||||
-telemetry_event #{
|
||||
event => [test_app, cache, miss],
|
||||
description => <<"Emitted at the start of the handler">>,
|
||||
measurements => <<"#{system_time => non_neg_integer()}">>,
|
||||
metadata => <<"#{}">>
|
||||
}.
|
||||
-telemetry_event #{
|
||||
event => [test_app, cache, hit],
|
||||
description => <<"Emitted at the end of the handler">>,
|
||||
measurements => <<"#{duration => non_neg_integer()}">>,
|
||||
metadata => <<"#{}">>
|
||||
}.
|
||||
|
||||
handler(Args) ->
|
||||
_ = telemetry:span(
|
||||
[test_app, handler],
|
||||
#{},
|
||||
fun() ->
|
||||
case Args of
|
||||
raise_exception ->
|
||||
binary_to_list("heh, already a list");
|
||||
_ -> {nested_span(), #{}}
|
||||
end
|
||||
end).
|
||||
|
||||
nested_span() ->
|
||||
_ = telemetry:span(
|
||||
[test_app, nested_span],
|
||||
#{},
|
||||
fun() ->
|
||||
{ok, #{}}
|
||||
end).
|
|
@ -0,0 +1,26 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%% @doc test_app public API
|
||||
%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(test_app_app).
|
||||
|
||||
-behaviour(application).
|
||||
|
||||
%% Application callbacks
|
||||
-export([start/2, stop/1]).
|
||||
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
|
||||
start(_StartType, _StartArgs) ->
|
||||
test_app_sup:start_link().
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
stop(_State) ->
|
||||
ok.
|
||||
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
%%====================================================================
|
|
@ -0,0 +1,38 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%% @doc test_app top level supervisor.
|
||||
%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(test_app_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
%%====================================================================
|
||||
%% API functions
|
||||
%%====================================================================
|
||||
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
|
||||
|
||||
%%====================================================================
|
||||
%% Supervisor callbacks
|
||||
%%====================================================================
|
||||
|
||||
%% Child :: #{id => Id, start => {M, F, A}}
|
||||
%% Optional keys are restart, shutdown, type, modules.
|
||||
%% Before OTP 18 tuples must be used to specify a child. e.g.
|
||||
%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
|
||||
init([]) ->
|
||||
{ok, {{one_for_all, 0, 1}, []}}.
|
||||
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
%%====================================================================
|
|
@ -0,0 +1,19 @@
|
|||
.rebar3
|
||||
_*
|
||||
.eunit
|
||||
*.o
|
||||
*.beam
|
||||
*.plt
|
||||
*.swp
|
||||
*.swo
|
||||
.erlang.cookie
|
||||
ebin
|
||||
log
|
||||
erl_crash.dump
|
||||
.rebar
|
||||
logs
|
||||
_build
|
||||
.idea
|
||||
*.iml
|
||||
rebar3.crashdump
|
||||
*~
|
|
@ -0,0 +1,191 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2020, Bryan Naegele <bryan@fourthtime.com>.
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
test_child_app
|
||||
=====
|
||||
|
||||
An OTP application
|
||||
|
||||
Build
|
||||
-----
|
||||
|
||||
$ rebar3 compile
|
|
@ -0,0 +1,7 @@
|
|||
{erl_opts, [debug_info]}.
|
||||
{deps, []}.
|
||||
|
||||
{shell, [
|
||||
% {config, "config/sys.config"},
|
||||
{apps, [test_child_app]}
|
||||
]}.
|
|
@ -0,0 +1 @@
|
|||
[].
|
|
@ -0,0 +1,15 @@
|
|||
{application, test_child_app,
|
||||
[{description, "An OTP application"},
|
||||
{vsn, "0.1.0"},
|
||||
{registered, []},
|
||||
{mod, {test_child_app_app, []}},
|
||||
{applications,
|
||||
[kernel,
|
||||
stdlib
|
||||
]},
|
||||
{env,[]},
|
||||
{modules, []},
|
||||
|
||||
{licenses, ["Apache 2.0"]},
|
||||
{links, []}
|
||||
]}.
|
|
@ -0,0 +1,27 @@
|
|||
-module(test_child_app).
|
||||
|
||||
-telemetry_event #{
|
||||
event => [test_child_app, extra_long, start],
|
||||
description => <<"Emitted at the start of the handler">>,
|
||||
measurements => <<"#{system_time => non_neg_integer()}">>,
|
||||
metadata => <<"#{}">>
|
||||
}.
|
||||
-telemetry_event #{
|
||||
event => [test_child_app, extra_long, stop],
|
||||
description => <<"Emitted at the end of the handler">>,
|
||||
measurements => <<"#{duration => non_neg_integer()}">>,
|
||||
metadata => <<"#{}">>
|
||||
}.
|
||||
|
||||
-telemetry_event #{
|
||||
event => [test_child_app, cache, hit],
|
||||
description => <<"Emitted at the start of the handler">>,
|
||||
measurements => <<"#{system_time => non_neg_integer()}">>,
|
||||
metadata => <<"#{}">>
|
||||
}.
|
||||
-telemetry_event #{
|
||||
event => [test_child_app, cache, miss],
|
||||
description => <<"Emitted at the end of the handler">>,
|
||||
measurements => <<"#{duration => non_neg_integer()}">>,
|
||||
metadata => <<"#{}">>
|
||||
}.
|
|
@ -0,0 +1,26 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%% @doc test_child_app public API
|
||||
%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(test_child_app_app).
|
||||
|
||||
-behaviour(application).
|
||||
|
||||
%% Application callbacks
|
||||
-export([start/2, stop/1]).
|
||||
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
|
||||
start(_StartType, _StartArgs) ->
|
||||
test_child_app_sup:start_link().
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
stop(_State) ->
|
||||
ok.
|
||||
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
%%====================================================================
|
|
@ -0,0 +1,38 @@
|
|||
%%%-------------------------------------------------------------------
|
||||
%% @doc test_child_app top level supervisor.
|
||||
%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(test_child_app_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
%%====================================================================
|
||||
%% API functions
|
||||
%%====================================================================
|
||||
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
|
||||
|
||||
%%====================================================================
|
||||
%% Supervisor callbacks
|
||||
%%====================================================================
|
||||
|
||||
%% Child :: #{id => Id, start => {M, F, A}}
|
||||
%% Optional keys are restart, shutdown, type, modules.
|
||||
%% Before OTP 18 tuples must be used to specify a child. e.g.
|
||||
%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
|
||||
init([]) ->
|
||||
{ok, {{one_for_all, 0, 1}, []}}.
|
||||
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
%%====================================================================
|
|
@ -0,0 +1,121 @@
|
|||
defmodule OpentelemetryTelemetry do
|
||||
@moduledoc """
|
||||
`OpentelemetryTelemetry` provides conveniences for leveraging `telemetry`
|
||||
events for `OpenTelemetry` bridge libraries.
|
||||
|
||||
## OpenTelemetry Contexts
|
||||
|
||||
`opentelemetry` does not automatically set current span context when ending
|
||||
another span. Since `telemetry` events are executed in separate handlers with
|
||||
no shared context, correlating individual events requires a mechanism to do so.
|
||||
Additionally, when ending telemetry-based spans, the user must set the correct
|
||||
parent context back as the current context. This ensures sibling spans are
|
||||
correctly correlated to the shared parent span.
|
||||
|
||||
This library provides helper functions to manage contexts automatically with
|
||||
`start_telemetry_span/4`, `set_current_telemetry_span/2`, and `end_telemetry_span/2`
|
||||
to give bridge library authors a mechanism for working with these challenges. Once
|
||||
`start_telemetry_span/4` or `set_current_telemetry_span/2` are called, users
|
||||
can use all of `OpenTelemetry` as normal. By providing the application tracer id
|
||||
and the event's metadata, the provided span functions will identify and manage
|
||||
span contexts automatically.
|
||||
|
||||
### Example Telemetry Event Handlers
|
||||
|
||||
```
|
||||
def handle_event(_event,
|
||||
%{system_time: start_time},
|
||||
metadata,
|
||||
%{type: :start, tracer_id: tracer_id, span_name: name}) do
|
||||
start_opts = %{start_time: start_time}
|
||||
OpentelemetryTelemetry.start_telemetry_span(tracer_id, name, metadata, start_opts)
|
||||
:ok
|
||||
end
|
||||
|
||||
def handle_event(_event,
|
||||
%{duration: duration},
|
||||
metadata,
|
||||
%{type: :stop, tracer_id: tracer_id}) do
|
||||
OpentelemetryTelemetry.set_current_telemetry_span(tracer_id, metadata)
|
||||
OpenTelemetry.Tracer.set_attribute(:duration, duration)
|
||||
OpentelemetryTelemetry.end_telemetry_span(tracer_id, metadata)
|
||||
:ok
|
||||
end
|
||||
|
||||
def handle_event(_event,
|
||||
%{duration: duration},
|
||||
%{kind: kind, reason: reason, stacktrace: stacktrace} = metadata,
|
||||
%{type: :exception, tracer_id: tracer_id}) do
|
||||
ctx = OpentelemetryTelemetry.set_current_telemetry_span(tracer_id, metadata),
|
||||
status = Opentelemetry.status(:error, to_string(reason, :utf8))
|
||||
OpenTelemetry.Span.record_exception(ctx, kind, reason, stacktrace, [duration: duration])
|
||||
OpenTelemetry.Tracer.set_status(status)
|
||||
OpentelemetryTelemetry.end_telemetry_span(tracer_id, metadata)
|
||||
:ok
|
||||
end
|
||||
def handle_event(_event, _measurements, _metadata, _config), do: :ok
|
||||
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
Span contexts are currently stored in the process dictionary, so spans can only
|
||||
be correlated within a single process at this time. This covers the primary use
|
||||
case where library authors have implemented `telemetry:with_span` or the pattern
|
||||
established in said function. Non-library authors should use opentelemetry directly
|
||||
wherever possible.
|
||||
|
||||
If the `event_metadata` includes a `telemetry_span_context` (introduced in telemetry
|
||||
`v0.4.3`), contexts are correlated by the `telemetry_span_context` id to guarantee
|
||||
the correct otel span context. Span events in earlier versions of `telemetry` are stored
|
||||
in a stack by `tracer_id` to lessen the likelihood of inadvertently closing the wrong
|
||||
span.
|
||||
"""
|
||||
|
||||
@typedoc """
|
||||
A span ctx for a telemetry-based span.
|
||||
"""
|
||||
@type telemetry_span_ctx() :: :opentelemetry.span_ctx()
|
||||
|
||||
@typedoc """
|
||||
The parent span ctx for a telemetry-based span. This is what the current span ctx was
|
||||
at the time of starting a telemetry-based span.
|
||||
"""
|
||||
@type parent_span_ctx() :: :opentelemetry.span_ctx()
|
||||
|
||||
@type ctx_set() :: {parent_span_ctx(), telemetry_span_ctx()}
|
||||
|
||||
@typep tracer_id() :: atom()
|
||||
|
||||
@doc """
|
||||
Start a telemetry-based span.
|
||||
"""
|
||||
@spec start_telemetry_span(
|
||||
tracer_id(),
|
||||
:opentelemetry.span_name(),
|
||||
:telemetry.event_metadata(),
|
||||
OpenTelemetry.Tracer.start_opts()
|
||||
) :: OpenTelemetry.span_ctx()
|
||||
defdelegate start_telemetry_span(tracer_id, span_name, event_metadata, start_opts),
|
||||
to: :otel_telemetry
|
||||
|
||||
@doc """
|
||||
Set the current span ctx based on the tracer_id and telemetry event metadata.
|
||||
"""
|
||||
@spec set_current_telemetry_span(tracer_id(), :telemetry.event_metadata()) ::
|
||||
OpenTelemetry.span_ctx()
|
||||
defdelegate set_current_telemetry_span(tracer_id, event_metadata), to: :otel_telemetry
|
||||
|
||||
@doc """
|
||||
End a telemetry-based span based on the `tracer_id` and telemetry event metadata
|
||||
and restore the current ctx to the span's parent ctx.
|
||||
"""
|
||||
@spec end_telemetry_span(tracer_id(), :telemetry.event_metadata()) :: :ok
|
||||
defdelegate end_telemetry_span(tracer_id, event_metadata), to: :otel_telemetry
|
||||
|
||||
@doc false
|
||||
defdelegate trace_application(app), to: :otel_telemetry
|
||||
|
||||
@doc false
|
||||
defdelegate trace_application(app, opts), to: :otel_telemetry
|
||||
end
|
|
@ -0,0 +1,101 @@
|
|||
defmodule OpentelemetryTelemetry.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
{app, desc} = load_app()
|
||||
config = load_config()
|
||||
|
||||
[
|
||||
app: app,
|
||||
version: version(Keyword.fetch!(desc, :vsn)),
|
||||
description: to_string(Keyword.fetch!(desc, :description)),
|
||||
elixir: "~> 1.10",
|
||||
start_permanent: Mix.env() == :prod,
|
||||
deps: deps(Keyword.fetch!(config, :deps)),
|
||||
name: "Opentelemetry Telemetry",
|
||||
source_url:
|
||||
"https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/utilities/opentelemetry_telemetry",
|
||||
docs: [
|
||||
markdown_processor: ExDoc.Markdown.Earmark,
|
||||
main: "OpentelemetryTelemetry",
|
||||
# logo: "path/to/logo.png",
|
||||
# erlang_docs()
|
||||
extras: []
|
||||
],
|
||||
aliases: [
|
||||
# when build docs first build edocs with rebar3
|
||||
docs: ["cmd rebar3 edoc", "docs"]
|
||||
],
|
||||
package: package()
|
||||
]
|
||||
end
|
||||
|
||||
defp version(version) when is_list(version) do
|
||||
List.to_string(version)
|
||||
end
|
||||
|
||||
defp version({:file, path}) do
|
||||
path
|
||||
|> File.read!()
|
||||
|> String.trim()
|
||||
end
|
||||
|
||||
# Run "mix help compile.app" to learn about applications.
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger]
|
||||
]
|
||||
end
|
||||
|
||||
defp deps(rebar) do
|
||||
rebar
|
||||
|> Enum.map(fn
|
||||
{dep, version} -> {dep, to_string(version)}
|
||||
dep when is_atom(dep) -> {dep, ">= 0.0.0"}
|
||||
end)
|
||||
|> Enum.concat([
|
||||
{:dialyxir, "~> 1.1", only: [:dev, :test], runtime: false},
|
||||
{:ex_doc, "~> 0.25.3", only: :dev, runtime: false},
|
||||
{:opentelemetry, "~> 1.0.0-rc.3", only: [:dev, :test]},
|
||||
{:opentelemetry_exporter, "~> 1.0.0-rc.3", only: [:dev, :test]}
|
||||
])
|
||||
end
|
||||
|
||||
defp package() do
|
||||
[
|
||||
description: "Bridge library between Telemetry events and OpenTelemetry Erlang",
|
||||
build_tools: ["rebar3", "mix"],
|
||||
files: ~w(lib mix.exs README.md LICENSE CODEOWNERS rebar.config rebar.lock VERSION src),
|
||||
licenses: ["Apache-2.0"],
|
||||
links: %{
|
||||
"GitHub" =>
|
||||
"https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/utilities/opentelemetry_telemetry",
|
||||
"OpenTelemetry Erlang" => "https://github.com/open-telemetry/opentelemetry-erlang",
|
||||
"OpenTelemetry Erlang Contrib" =>
|
||||
"https://github.com/open-telemetry/opentelemetry-erlang-contrib",
|
||||
"OpenTelemetry.io" => "https://opentelemetry.io"
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
def erlang_docs() do
|
||||
files =
|
||||
for file <- Path.wildcard("edoc/*.md"),
|
||||
file != "edoc/README.md",
|
||||
do: {String.to_atom(file), [title: Path.basename(file, ".md")]}
|
||||
|
||||
[{:"README.md", [title: "Overview"]} | files]
|
||||
end
|
||||
|
||||
defp load_config do
|
||||
{:ok, config} = :file.consult('rebar.config')
|
||||
|
||||
config
|
||||
end
|
||||
|
||||
defp load_app do
|
||||
{:ok, [{:application, name, desc}]} = :file.consult('src/opentelemetry_telemetry.app.src')
|
||||
|
||||
{name, desc}
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
%{
|
||||
"acceptor_pool": {:hex, :acceptor_pool, "1.0.0", "43c20d2acae35f0c2bcd64f9d2bde267e459f0f3fd23dab26485bf518c281b21", [:rebar3], [], "hexpm", "0cbcd83fdc8b9ad2eee2067ef8b91a14858a5883cb7cd800e6fcd5803e158788"},
|
||||
"chatterbox": {:hex, :ts_chatterbox, "0.11.0", "b8f372c706023eb0de5bf2976764edb27c70fe67052c88c1f6a66b3a5626847f", [:rebar3], [{:hpack, "~>0.2.3", [hex: :hpack_erl, repo: "hexpm", optional: false]}], "hexpm", "722fe2bad52913ab7e87d849fc6370375f0c961ffb2f0b5e6d647c9170c382a6"},
|
||||
"cmark": {:hex, :cmark, "0.9.0", "c0e673019e125eb5878b6c5610af919d737e881369e0cd2247c89e767f42c029", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "0cfb4d8888bc801f2decc23eee3b3b756b682dff976d15a46861a596fdb00079"},
|
||||
"ctx": {:hex, :ctx, "0.6.0", "8ff88b70e6400c4df90142e7f130625b82086077a45364a78d208ed3ed53c7fe", [:rebar3], [], "hexpm", "a14ed2d1b67723dbebbe423b28d7615eb0bdcba6ff28f2d1f1b0a7e1d4aa5fc2"},
|
||||
"dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},
|
||||
"earmark": {:hex, :earmark, "1.4.5", "62ffd3bd7722fb7a7b1ecd2419ea0b458c356e7168c1f5d65caf09b4fbdd13c8", [:mix], [], "hexpm", "b7d0e6263d83dc27141a523467799a685965bf8b13b6743413f19a7079843f4f"},
|
||||
"earmark_parser": {:hex, :earmark_parser, "1.4.15", "b29e8e729f4aa4a00436580dcc2c9c5c51890613457c193cc8525c388ccb2f06", [:mix], [], "hexpm", "044523d6438ea19c1b8ec877ec221b008661d3c27e3b848f4c879f500421ca5c"},
|
||||
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
|
||||
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.25.3", "3edf6a0d70a39d2eafde030b8895501b1c93692effcbd21347296c18e47618ce", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "9ebebc2169ec732a38e9e779fd0418c9189b3ca93f4a676c961be6c1527913f5"},
|
||||
"gproc": {:hex, :gproc, "0.8.0", "cea02c578589c61e5341fce149ea36ccef236cc2ecac8691fba408e7ea77ec2f", [:rebar3], [], "hexpm", "580adafa56463b75263ef5a5df4c86af321f68694e7786cb057fd805d1e2a7de"},
|
||||
"grpcbox": {:hex, :grpcbox, "0.14.0", "3eb321bcd2275baf8b54cf381feb7b0559a50c02544de28fda039c7f2f9d1a7a", [:rebar3], [{:acceptor_pool, "~>1.0.0", [hex: :acceptor_pool, repo: "hexpm", optional: false]}, {:chatterbox, "~>0.11.0", [hex: :ts_chatterbox, repo: "hexpm", optional: false]}, {:ctx, "~>0.6.0", [hex: :ctx, repo: "hexpm", optional: false]}, {:gproc, "~>0.8.0", [hex: :gproc, repo: "hexpm", optional: false]}], "hexpm", "e24159b7b6d3f9869bbe528845c0125fed2259366ba908fd04a1f45fe81d0660"},
|
||||
"hpack": {:hex, :hpack_erl, "0.2.3", "17670f83ff984ae6cd74b1c456edde906d27ff013740ee4d9efaa4f1bf999633", [:rebar3], [], "hexpm", "06f580167c4b8b8a6429040df36cc93bba6d571faeaec1b28816523379cbb23a"},
|
||||
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
|
||||
"makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"},
|
||||
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
|
||||
"nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
|
||||
"opentelemetry": {:hex, :opentelemetry, "1.0.0-rc.3", "d2698bee882c354274563ee85d097bb736a9adb8d8ed376a4deea0cd3a14bb31", [:rebar3], [{:opentelemetry_api, "~> 1.0.0-rc.3", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "c9105933df0d783d94cf08d79206eb8d6578abc0bcbd498d0b497ec62a4e30a8"},
|
||||
"opentelemetry_api": {:hex, :opentelemetry_api, "1.0.0-rc.3.1", "d183663c178f317a109a267b3c3664d09db22829a4d4eea8d9af46ed3e5bee05", [:mix, :rebar3], [], "hexpm", "4b836cec1b531080c310fa54afca6e523984a1f6c1aeb5d4da537dad9e309ce9"},
|
||||
"opentelemetry_exporter": {:hex, :opentelemetry_exporter, "1.0.0-rc.3", "76f5657d4c94a12003d9ed2c8da1023c815e98f5553184dbb0cdaeec76db676d", [:rebar3], [{:grpcbox, ">= 0.0.0", [hex: :grpcbox, repo: "hexpm", optional: false]}, {:opentelemetry, "~> 1.0.0-rc.3", [hex: :opentelemetry, repo: "hexpm", optional: false]}, {:opentelemetry_api, "~> 1.0.0-rc.3", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "267f0e4c3f1f5557cc7ad6ac71d66b8eaf7b3b56fde942c21f8a0bc96174fe1e"},
|
||||
"telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"},
|
||||
"telemetry_registry": {:hex, :telemetry_registry, "0.3.0", "6768f151ea53fc0fbca70dbff5b20a8d663ee4e0c0b2ae589590e08658e76f1e", [:mix, :rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "492e2adbc609f3e79ece7f29fec363a97a2c484ac78a83098535d6564781e917"},
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
{erl_opts, [debug_info]}.
|
||||
{deps, [
|
||||
{opentelemetry_api, "~> 1.0.0-rc.3"},
|
||||
{telemetry, "~> 1.0"},
|
||||
{telemetry_registry, "~> 0.3.0"}
|
||||
]}.
|
||||
|
||||
{project_plugins, [covertool,
|
||||
erlfmt]}.
|
||||
{profiles,
|
||||
[{docs, [{deps, [edown]},
|
||||
{edoc_opts,
|
||||
[{doclet, edown_doclet},
|
||||
{preprocess, true},
|
||||
{dir, "edoc"},
|
||||
{subpackages, true}]}]},
|
||||
{test, [{erl_opts, [nowarn_export_all]},
|
||||
{deps, [
|
||||
{opentelemetry, "~> 1.0.0-rc.3"},
|
||||
{opentelemetry_exporter, "~> 1.0.0-rc.3"},
|
||||
{test_app, "~> 0.1"}
|
||||
]},
|
||||
{paths, ["src", "test/support"]},
|
||||
{ct_opts, [{ct_hooks, [cth_surefire]}]}]}]}.
|
||||
|
||||
{xref_checks, [undefined_function_calls, undefined_functions,
|
||||
deprecated_function_calls, deprecated_functions]}.
|
||||
{xref_ignores, []}.
|
||||
|
||||
{cover_enabled, true}.
|
||||
{cover_export_enabled, true}.
|
||||
{covertool, [{coverdata_files, ["ct.coverdata"]}]}.
|
|
@ -0,0 +1,14 @@
|
|||
{"1.2.0",
|
||||
[{<<"opentelemetry_api">>,{pkg,<<"opentelemetry_api">>,<<"1.0.0-rc.3.1">>},0},
|
||||
{<<"telemetry">>,{pkg,<<"telemetry">>,<<"1.0.0">>},0},
|
||||
{<<"telemetry_registry">>,{pkg,<<"telemetry_registry">>,<<"0.3.0">>},0}]}.
|
||||
[
|
||||
{pkg_hash,[
|
||||
{<<"opentelemetry_api">>, <<"D183663C178F317A109A267B3C3664D09DB22829A4D4EEA8D9AF46ED3E5BEE05">>},
|
||||
{<<"telemetry">>, <<"0F453A102CDF13D506B7C0AB158324C337C41F1CC7548F0BC0E130BBF0AE9452">>},
|
||||
{<<"telemetry_registry">>, <<"6768F151EA53FC0FBCA70DBFF5B20A8D663EE4E0C0B2AE589590E08658E76F1E">>}]},
|
||||
{pkg_hash_ext,[
|
||||
{<<"opentelemetry_api">>, <<"4B836CEC1B531080C310FA54AFCA6E523984A1F6C1AEB5D4DA537DAD9E309CE9">>},
|
||||
{<<"telemetry">>, <<"73BC09FA59B4A0284EFB4624335583C528E07EC9AE76ACA96EA0673850AEC57A">>},
|
||||
{<<"telemetry_registry">>, <<"492E2ADBC609F3E79ECE7F29FEC363A97A2C484AC78A83098535D6564781E917">>}]}
|
||||
].
|
|
@ -0,0 +1,18 @@
|
|||
{application, opentelemetry_telemetry,
|
||||
[{description, "Telemetry to OpenTelemetry Bridge"},
|
||||
{vsn, {file, "VERSION"}},
|
||||
{registered, []},
|
||||
{applications,
|
||||
[kernel,
|
||||
stdlib,
|
||||
opentelemetry,
|
||||
opentelemetry_api,
|
||||
telemetry,
|
||||
telemetry_registry
|
||||
]},
|
||||
{env,[]},
|
||||
{modules, []},
|
||||
|
||||
{licenses, ["Apache-2.0"]},
|
||||
{links, [{"GitHub", "https://github.com/opentelemetry-beam/opentelemetry_telemetry"}]}
|
||||
]}.
|
|
@ -0,0 +1,167 @@
|
|||
-module(otel_telemetry).
|
||||
|
||||
-include_lib("opentelemetry_api/include/opentelemetry.hrl").
|
||||
|
||||
-export([
|
||||
init/1,
|
||||
init/2,
|
||||
handle_event/4,
|
||||
start_telemetry_span/4,
|
||||
set_current_telemetry_span/2,
|
||||
end_telemetry_span/2,
|
||||
trace_application/1,
|
||||
trace_application/2]).
|
||||
|
||||
-type telemetry_span_ctx() :: opentelemetry:span_ctx().
|
||||
-type parent_span_ctx() :: opentelemetry:span_ctx().
|
||||
|
||||
-type ctx_set() :: {parent_span_ctx(), telemetry_span_ctx()}.
|
||||
|
||||
-spec init(atom()) -> ok.
|
||||
init(Application) ->
|
||||
init(Application, []).
|
||||
|
||||
-spec init(atom(), []) -> ok.
|
||||
init(_Application, _Opts) ->
|
||||
ok.
|
||||
|
||||
trace_application(Application) ->
|
||||
trace_application(Application, []).
|
||||
|
||||
trace_application(Application, _Opts) ->
|
||||
_ = telemetry_registry:discover_all([Application]),
|
||||
AllEvents = telemetry_registry:list_events(),
|
||||
SpannableEvents = telemetry_registry:spannable_events(),
|
||||
_ = register_event_handlers(SpannableEvents, AllEvents),
|
||||
ok.
|
||||
|
||||
-spec start_telemetry_span(atom(), opentelemetry:span_name(), telemetry:event_metadata(), otel_span:start_opts()) -> opentelemetry:span_ctx().
|
||||
start_telemetry_span(TracerId, SpanName, EventMetadata, Opts) ->
|
||||
ParentCtx = otel_tracer:current_span_ctx(),
|
||||
Tracer = opentelemetry:get_tracer(TracerId),
|
||||
Ctx = otel_tracer:start_span(Tracer, SpanName, Opts),
|
||||
otel_tracer:set_current_span(Ctx),
|
||||
_ = store_ctx({ParentCtx, Ctx}, TracerId, EventMetadata),
|
||||
Ctx.
|
||||
|
||||
-spec set_current_telemetry_span(atom(), telemetry:event_metadata()) -> opentelemetry:span_ctx() | undefined.
|
||||
set_current_telemetry_span(TracerId, EventMetadata) ->
|
||||
case fetch_telemetry_span_ctx(TracerId, EventMetadata) of
|
||||
{_ParentCtx, Ctx} ->
|
||||
otel_tracer:set_current_span(Ctx),
|
||||
Ctx;
|
||||
undefined ->
|
||||
undefined
|
||||
end.
|
||||
|
||||
-spec end_telemetry_span(atom(), telemetry:event_metadata()) -> ok.
|
||||
end_telemetry_span(TracerId, EventMetadata) ->
|
||||
{ParentCtx, Ctx} = pop_ctx(TracerId, EventMetadata),
|
||||
otel_span:end_span(Ctx),
|
||||
otel_tracer:set_current_span(ParentCtx),
|
||||
ok.
|
||||
|
||||
-spec store_ctx(ctx_set(), atom(), telemetry:event_metadata()) -> ok.
|
||||
store_ctx(SpanCtxSet, TracerId, EventMetadata) ->
|
||||
case maps:get(telemetry_span_context, EventMetadata, undefined) of
|
||||
undefined ->
|
||||
push_to_tracer_stack(SpanCtxSet, TracerId);
|
||||
TelemetryCtx ->
|
||||
erlang:put({otel_telemetry, TelemetryCtx}, SpanCtxSet)
|
||||
end,
|
||||
ok.
|
||||
|
||||
-spec push_to_tracer_stack(ctx_set(), atom()) -> ok.
|
||||
push_to_tracer_stack(SpanCtxSet, TracerId) ->
|
||||
case erlang:get({otel_telemetry, TracerId}) of
|
||||
undefined ->
|
||||
erlang:put({otel_telemetry, TracerId}, [SpanCtxSet]);
|
||||
Stack ->
|
||||
erlang:put({otel_telemetry, TracerId}, [SpanCtxSet | Stack])
|
||||
end.
|
||||
|
||||
-spec fetch_telemetry_span_ctx(atom(), telemetry:event_metadata()) -> ctx_set() | undefined.
|
||||
fetch_telemetry_span_ctx(TracerId, EventMetadata) ->
|
||||
case maps:get(telemetry_span_context, EventMetadata, undefined) of
|
||||
undefined ->
|
||||
peek_from_tracer_stack(TracerId);
|
||||
TelemetryCtx ->
|
||||
erlang:get({otel_telemetry, TelemetryCtx})
|
||||
end.
|
||||
|
||||
-spec peek_from_tracer_stack(atom()) -> ctx_set() | undefined.
|
||||
peek_from_tracer_stack(TracerId) ->
|
||||
case erlang:get({otel_telemetry, TracerId}) of
|
||||
undefined ->
|
||||
undefined;
|
||||
[SpanCtxSet | _Rest] ->
|
||||
SpanCtxSet
|
||||
end.
|
||||
|
||||
-spec pop_ctx(atom(), telemetry:event_metadata()) -> ctx_set().
|
||||
pop_ctx(TracerId, EventMetadata) ->
|
||||
case maps:get(telemetry_span_context, EventMetadata, undefined) of
|
||||
undefined ->
|
||||
pop_from_tracer_stack(TracerId);
|
||||
TelemetryCtx ->
|
||||
erlang:erase({otel_telemetry, TelemetryCtx})
|
||||
end.
|
||||
|
||||
pop_from_tracer_stack(TracerId) ->
|
||||
case erlang:get({otel_telemetry, TracerId}) of
|
||||
undefined ->
|
||||
undefined;
|
||||
[SpanCtxSet | Rest] ->
|
||||
erlang:put({otel_telemetry, TracerId}, Rest),
|
||||
SpanCtxSet
|
||||
end.
|
||||
|
||||
register_event_handlers(SpannableEvents, AllEvents) ->
|
||||
lists:foldl(fun ({Prefix, Suffixes}, Handlers) ->
|
||||
TracerId = tracer_id_for_events(Prefix, Suffixes, AllEvents),
|
||||
NewHandlers = [attach_handler(Prefix, Suffix, TracerId)
|
||||
|| Suffix <- Suffixes],
|
||||
NewHandlers ++ Handlers
|
||||
end,
|
||||
[],
|
||||
SpannableEvents).
|
||||
|
||||
attach_handler(Prefix, Suffix, TracerId) ->
|
||||
Event = Prefix ++ [Suffix],
|
||||
SpanName = list_to_binary(lists:join("_",
|
||||
[atom_to_binary(Segment, utf8) || Segment <- Prefix])),
|
||||
Config = #{tracer_id => TracerId, type => Suffix, span_name => SpanName},
|
||||
Handler = fun ?MODULE:handle_event/4,
|
||||
telemetry:attach({?MODULE, Event}, Event, Handler, Config).
|
||||
|
||||
tracer_id_for_events(Prefix, [Suffix | _], AllEvents) ->
|
||||
Event = Prefix ++ [Suffix],
|
||||
{Event, Module, _Metadata} = lists:keyfind(Event, 1, AllEvents),
|
||||
Module.
|
||||
|
||||
handle_event(_Event,
|
||||
_Measurements,
|
||||
Metadata,
|
||||
#{type := start, tracer_id := TracerId, span_name := Name}) ->
|
||||
_Ctx = start_telemetry_span(TracerId, Name, Metadata, #{}),
|
||||
ok;
|
||||
handle_event(_Event,
|
||||
_Measurements,
|
||||
Metadata,
|
||||
#{type := stop, tracer_id := TracerId}) ->
|
||||
Ctx = set_current_telemetry_span(TracerId, Metadata),
|
||||
end_telemetry_span(TracerId, Metadata),
|
||||
ok;
|
||||
handle_event(_Event,
|
||||
_Measurements,
|
||||
#{kind := Kind, reason := Reason, stacktrace := Stacktrace} = Metadata,
|
||||
#{type := exception, tracer_id := TracerId}) ->
|
||||
Ctx = set_current_telemetry_span(TracerId, Metadata),
|
||||
Status = opentelemetry:status(?OTEL_STATUS_ERROR, atom_to_binary(Reason, utf8)),
|
||||
otel_span:record_exception(Ctx, Kind, Reason, Stacktrace, []),
|
||||
otel_span:set_status(Ctx, Status),
|
||||
end_telemetry_span(TracerId, Metadata),
|
||||
ok;
|
||||
handle_event(_Event, _Measurements, _Metadata, _Config) ->
|
||||
ok.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
defmodule OpentelemetryTelemetryTest do
|
||||
use ExUnit.Case
|
||||
end
|
|
@ -0,0 +1,83 @@
|
|||
-module(otel_telemetry_SUITE).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include_lib("common_test/include/ct.hrl").
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
-include_lib("opentelemetry_api/include/opentelemetry.hrl").
|
||||
-include_lib("opentelemetry/include/otel_span.hrl").
|
||||
-include_lib("opentelemetry_api/include/otel_tracer.hrl").
|
||||
|
||||
all() -> [
|
||||
telemetry_span_handling
|
||||
].
|
||||
|
||||
init_per_suite(Config) ->
|
||||
ok = application:load(opentelemetry_telemetry),
|
||||
ok = application:load(opentelemetry),
|
||||
application:set_env(opentelemetry, processors, [{otel_batch_processor, #{scheduled_delay_ms => 1}}]),
|
||||
Config.
|
||||
|
||||
end_per_suite(_Config) ->
|
||||
ok = application:unload(opentelemetry),
|
||||
ok.
|
||||
|
||||
init_per_testcase(_, Config) ->
|
||||
{ok, _} = application:ensure_all_started(telemetry),
|
||||
{ok, _} = application:ensure_all_started(telemetry_registry),
|
||||
{ok, _} = application:ensure_all_started(test_app),
|
||||
{ok, _} = application:ensure_all_started(opentelemetry_telemetry),
|
||||
otel_batch_processor:set_exporter(otel_exporter_pid, self()),
|
||||
otel_telemetry:trace_application(test_app),
|
||||
opentelemetry:register_tracer(test_tracer, "0.1.0"),
|
||||
Config.
|
||||
|
||||
end_per_testcase(_, Config) ->
|
||||
application:stop(telemetry),
|
||||
application:stop(telemetry_registry),
|
||||
application:stop(test_app),
|
||||
application:stop(opentelemetry_telemetry),
|
||||
application:stop(opentelemetry),
|
||||
Config.
|
||||
|
||||
telemetry_span_handling(_Config) ->
|
||||
SpanCtx1 = ?start_span(<<"span-1">>),
|
||||
?set_current_span(SpanCtx1),
|
||||
_Result = test_app:handler(ok),
|
||||
?assertMatch(SpanCtx1, ?current_span_ctx),
|
||||
try test_app:handler(raise_exception) of
|
||||
_ -> ok
|
||||
catch
|
||||
error:badarg -> ok
|
||||
end,
|
||||
?assertMatch(SpanCtx1, ?current_span_ctx),
|
||||
?set_attribute(<<"attribute">>, 1),
|
||||
?end_span(),
|
||||
{_, Span3Parent} = successful_span_listener(<<"test_app_nested_span">>),
|
||||
{Span2, Span2Parent} = successful_span_listener(<<"test_app_handler">>),
|
||||
{_, ExceptionSpanParent} = exception_span_listener(<<"test_app_handler">>),
|
||||
{Span1, undefined} = successful_span_listener(<<"span-1">>),
|
||||
?assertEqual(Span2Parent, Span1),
|
||||
?assertEqual(ExceptionSpanParent, Span1),
|
||||
?assertEqual(Span3Parent, Span2),
|
||||
ok.
|
||||
|
||||
successful_span_listener(Name) ->
|
||||
receive
|
||||
{span, #span{name=Name,attributes=Attributes,parent_span_id=ParentId,span_id=Id}} ->
|
||||
{Id, ParentId}
|
||||
after
|
||||
5000 ->
|
||||
error(timeout)
|
||||
end.
|
||||
|
||||
exception_span_listener(Name) ->
|
||||
receive
|
||||
{span, #span{name=Name,events=Events,status=Status,parent_span_id=ParentId,span_id=Id}} ->
|
||||
?assertEqual({status,error,<<"badarg">>}, Status),
|
||||
?assertEqual(1, erlang:length(Events)),
|
||||
{Id, ParentId}
|
||||
after
|
||||
5000 ->
|
||||
error(timeout)
|
||||
end.
|
|
@ -0,0 +1 @@
|
|||
ExUnit.start()
|
Loading…
Reference in New Issue