-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rename integration namespace to instrumentation
Writing the guides in the OpenTelemetry::Guides namespace revealed that while the specification _always_ refers to "instrumentation libraries", this distribution _always_ used the term "integration" instead. This (breaking) change renames the ::Integration namespace to more closely align with the specification, hopefuly reducing any confusion that might arise there. Since some code might already be relying on that legacy namespace, this change makes efforts to continue to support the legacy namespace, although this will likely be removed in the future.
- Loading branch information
Showing
23 changed files
with
356 additions
and
271 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package OpenTelemetry::Instrumentation; | ||
# ABSTRACT: Top-level interface for OpenTelemetry instrumentations | ||
|
||
our $VERSION = '0.026'; | ||
|
||
use strict; | ||
use warnings; | ||
use experimental 'signatures'; | ||
|
||
use Feature::Compat::Try; | ||
use List::Util 'uniqstr'; | ||
use Module::Runtime (); | ||
use Module::Pluggable search_path => [qw( | ||
OpenTelemetry::Instrumentation | ||
OpenTelemetry::Integration | ||
)]; | ||
use Ref::Util 'is_hashref'; | ||
|
||
use Log::Any; | ||
my $logger = Log::Any->get_logger( category => 'OpenTelemetry' ); | ||
|
||
# To be overriden by instrumentations | ||
sub dependencies { } | ||
sub uninstall { } # experimental | ||
|
||
my sub module_exists ($module) { | ||
my $file = Module::Runtime::module_notional_filename $module; | ||
for (@INC) { | ||
return 1 if -e "$_/$file"; | ||
} | ||
return 0; | ||
} | ||
|
||
my @installed; | ||
sub import ( $class, @args ) { | ||
return unless @args; | ||
|
||
my $all = $args[0] =~ /^[:-]all$/ && shift @args; | ||
|
||
# Inlined from OpenTelemetry::Common to read Perl-specific config | ||
my $legacy_support = $ENV{OTEL_PERL_USE_LEGACY_INSTRUMENTATIONS} // 1; | ||
$legacy_support | ||
= $legacy_support =~ /^true$/i ? 1 | ||
: $legacy_support =~ /^false$/i ? 0 | ||
: $legacy_support; | ||
|
||
my %configuration; | ||
while ( my $key = shift @args ) { | ||
my $options = is_hashref $args[0] ? shift @args : {}; | ||
|
||
# Legacy namespace support. If we are loading an integration | ||
# by name which does not exist in INC in the new namespace, | ||
# but does exist in the legacy namespace, we use the legacy | ||
# name instead. | ||
my $module = __PACKAGE__ . '::' . $key; | ||
if ( $legacy_support && !module_exists($module) ) { | ||
my $legacy = $module =~ s/^OpenTelemetry::Instrumentation/OpenTelemetry::Integration/r; | ||
$module = $legacy if module_exists($legacy); | ||
} | ||
|
||
$configuration{$module} = $options; | ||
} | ||
|
||
if ($all) { | ||
for my $plugin ($class->plugins) { | ||
if ( $plugin =~ /^OpenTelemetry::Instrumentation/ ) { | ||
$configuration{$plugin} //= {}; | ||
next; | ||
} | ||
|
||
next unless $legacy_support; | ||
|
||
my $canonical = $plugin =~ s/^OpenTelemetry::Integration/OpenTelemetry::Instrumentation/r; | ||
next if $configuration{$canonical}; | ||
|
||
$configuration{$plugin} //= {}; | ||
} | ||
} | ||
|
||
for my $package ( keys %configuration ) { | ||
try { | ||
$logger->tracef('Loading %s', $package); | ||
|
||
Module::Runtime::require_module($package); | ||
|
||
# We only load dependencies if we are not loading every module | ||
unless ($all) { | ||
Module::Runtime::require_module($_) for $package->dependencies; | ||
} | ||
|
||
my $ok = $package->install( %{ $configuration{ $package } } ); | ||
|
||
if ($ok) { | ||
push @installed, $package; | ||
} | ||
else { | ||
$logger->tracef("$package did not install itself"); | ||
} | ||
|
||
} catch ($e) { | ||
# Just a warning, if we're loading everything then | ||
# we shouldn't cause chaos just because something | ||
# doesn't happen to be available. | ||
$logger->warnf('Unable to load %s: %s', $package, $e); | ||
} | ||
} | ||
} | ||
|
||
sub unimport ( $class, @args ) { | ||
@args = @installed unless @args; | ||
$_->uninstall for @args; | ||
return; | ||
} | ||
|
||
1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
=encoding utf8 | ||
|
||
=head1 NAME | ||
|
||
OpenTelemetry::Instrumentation - Top-level interface for OpenTelemetry instrumentations | ||
|
||
=head1 SYNOPSIS | ||
|
||
# Load instrumentations for specific modules | ||
use OpenTelemetry::Instrumentation qw( HTTP::Tiny DBI ); | ||
|
||
# Some instrumentations can take additional options | ||
use OpenTelemetry::Instrumentation 'HTTP::Tiny' => \%options; | ||
|
||
# Load every available instrumentation | ||
use OpenTelemetry::Instrumentation -all; | ||
|
||
=head1 DESCRIPTION | ||
|
||
This is the base class for handling tracing instrumentation with other CPAN | ||
modules. | ||
|
||
It provides functionality for loading available instrumentations | ||
via the import list on a C<use> statement: | ||
|
||
=over 4 | ||
|
||
=item * | ||
|
||
with C<-all>, all available OpenTelemetry instrumentations will be loaded, | ||
if the module the instrumentation is for has already been loaded | ||
|
||
=item * | ||
|
||
with a specific list of modules, they will be loaded (even if they haven't | ||
been before) and instrumentations for them will be applied if available | ||
|
||
=back | ||
|
||
This means that you can expect L<HTTP::Tiny> to be traced if you have the | ||
L<OpenTelemetry::Instrumentation::HTTP::Tiny> module installed and you do this: | ||
|
||
use OpenTelemetry::Instrumentation 'HTTP::Tiny'; | ||
|
||
or this: | ||
|
||
use HTTP::Tiny; | ||
use OpenTelemetry::Instrumentation -all; | ||
|
||
but it will B<not> be traced if you do this: | ||
|
||
use OpenTelemetry::Instrumentation -all; | ||
use HTTP::Tiny; | ||
|
||
The rationale behind this apparently inconsistent behaviour is that, with a | ||
large install, C<:all> might load unexpected instrumentations. This behaviour | ||
allows you instead to add this line after your module imports, and any | ||
functionality that is actively being used in the code (for which an | ||
instrumentation module is available) would gain tracing. | ||
|
||
=head2 Legacy namespace | ||
|
||
With the release of version 0.026, the namespace for instrumentation | ||
libraries moved from L<OpenTelemetry::Integration> to this one. The legacy | ||
namespace is still supported for backwards compatibility, but should not be | ||
used for new code. | ||
|
||
To support it, this module will look for instrumentation libraries in both | ||
namespaces, and prefer the ones in the new namespace over those in the legacy | ||
one. Instrumentation libraries in the legacy namespace will only be loaded if | ||
no equivalent instrumentation exists in the new namespace. | ||
|
||
This behaviour is enabled by default, but can be disabled by setting the | ||
C<OTEL_PERL_USE_LEGACY_INSTRUMENTATIONS> environment variable to a false value. | ||
|
||
=head1 WRITING INTEGRATIONS | ||
|
||
Additional instrumentations can be written and used as long as they are in the | ||
the OpenTelemetry::Instrumentation namespace. They should subclass this module | ||
(OpenTelemetry::Instrumentation) and should implement an C<install> class method | ||
as described in detail below. Other methods described in this section are | ||
optional, but can be used to provide additional features. | ||
|
||
=head2 install | ||
|
||
$bool = $class->install(%configuration); | ||
|
||
Installs the instrumentation. Will be called with a (possibly empty) list of | ||
key/value pairs with configuration options, and is expected to return a | ||
true value if the instrumentation was installed, or false otherwise. | ||
|
||
An example implementation of this method might look like the following: | ||
|
||
package OpenTelemetry::Instrumentation::Foo::Bar; | ||
|
||
use experimental 'signatures'; | ||
use Class::Inspector; | ||
use Class::Method::Modifiers 'install_modifier'; | ||
|
||
my $loaded; | ||
sub install ( $class, %config ) { | ||
return if $loaded++; | ||
return unless Class::Inspector->loaded('Foo::Bar'); | ||
|
||
install_modifier 'Foo::Bar' => around => reticulate_splines => sub { | ||
my ( $orig, $self, @args ) = @_; | ||
... | ||
my $value = $self->$orig(@args); | ||
... | ||
return $value; | ||
}; | ||
|
||
return 1; | ||
} | ||
|
||
=head2 dependencies | ||
|
||
@package_names = $class->dependencies; | ||
|
||
Should return the names of the packages that should be loaded to install | ||
this instrumentation. This method will be called in list context when loading | ||
dependencies automatically (ie. not when using the C<all> flag) to load | ||
the dependencies before calling L</install>. | ||
|
||
=head1 COPYRIGHT | ||
|
||
This software is copyright (c) 2023 by José Joaquín Atria. | ||
|
||
This is free software; you can redistribute it and/or modify it under the same | ||
terms as the Perl 5 programming language system itself. |
Oops, something went wrong.