1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15+ from functools import cached_property
1516from logging import getLogger
1617from os import environ
1718
18- from opentelemetry .instrumentation .dependencies import DependencyConflictError
19+ from opentelemetry .instrumentation .dependencies import (
20+ get_dist_dependency_conflicts ,
21+ )
1922from opentelemetry .instrumentation .distro import BaseDistro , DefaultDistro
2023from opentelemetry .instrumentation .environment_variables import (
2124 OTEL_PYTHON_CONFIGURATOR ,
2225 OTEL_PYTHON_DISABLED_INSTRUMENTATIONS ,
2326 OTEL_PYTHON_DISTRO ,
2427)
2528from opentelemetry .instrumentation .version import __version__
26- from opentelemetry .util ._importlib_metadata import entry_points
29+ from opentelemetry .util ._importlib_metadata import (
30+ EntryPoint ,
31+ distributions ,
32+ entry_points ,
33+ )
2734
2835_logger = getLogger (__name__ )
2936
3037
38+ class _EntryPointDistFinder :
39+ @cached_property
40+ def _mapping (self ):
41+ return {
42+ self ._key_for (ep ): dist
43+ for dist in distributions ()
44+ for ep in dist .entry_points
45+ }
46+
47+ def dist_for (self , entry_point : EntryPoint ):
48+ dist = getattr (entry_point , "dist" , None )
49+ if dist :
50+ return dist
51+
52+ return self ._mapping .get (self ._key_for (entry_point ))
53+
54+ @staticmethod
55+ def _key_for (entry_point : EntryPoint ):
56+ return f"{ entry_point .group } :{ entry_point .name } :{ entry_point .value } "
57+
58+
3159def _load_distro () -> BaseDistro :
3260 distro_name = environ .get (OTEL_PYTHON_DISTRO , None )
3361 for entry_point in entry_points (group = "opentelemetry_distro" ):
@@ -55,6 +83,7 @@ def _load_distro() -> BaseDistro:
5583
5684def _load_instrumentors (distro ):
5785 package_to_exclude = environ .get (OTEL_PYTHON_DISABLED_INSTRUMENTATIONS , [])
86+ entry_point_finder = _EntryPointDistFinder ()
5887 if isinstance (package_to_exclude , str ):
5988 package_to_exclude = package_to_exclude .split ("," )
6089 # to handle users entering "requests , flask" or "requests, flask" with spaces
@@ -64,44 +93,77 @@ def _load_instrumentors(distro):
6493 entry_point .load ()()
6594
6695 for entry_point in entry_points (group = "opentelemetry_instrumentor" ):
96+ print (entry_point .name )
6797 if entry_point .name in package_to_exclude :
6898 _logger .debug (
6999 "Instrumentation skipped for library %s" , entry_point .name
70100 )
71101 continue
72102
73103 try :
104+ entry_point_dist = entry_point_finder .dist_for (entry_point )
105+ conflict = get_dist_dependency_conflicts (entry_point_dist )
106+ if conflict :
107+ print (
108+ "conflict found %s: %s" % (
109+ entry_point .name , conflict
110+ )
111+ )
112+ _logger .debug (
113+ "Skipping instrumentation %s: %s" ,
114+ entry_point .name ,
115+ conflict ,
116+ )
117+ continue
118+
119+ # tell instrumentation to not run dep checks again as we already did it above
74120 distro .load_instrumentor (
75121 entry_point , raise_exception_on_conflict = True
76122 )
77123 _logger .debug ("Instrumented %s" , entry_point .name )
78- except DependencyConflictError as exc :
79- _logger .debug (
80- "Skipping instrumentation %s: %s" ,
81- entry_point .name ,
82- exc .conflict ,
83- )
84- continue
85- except ModuleNotFoundError as exc :
86- # ModuleNotFoundError is raised when the library is not installed
87- # and the instrumentation is not required to be loaded.
88- # See https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3421
89- _logger .debug (
90- "Skipping instrumentation %s: %s" , entry_point .name , exc .msg
91- )
92- continue
124+ print ("Instrumented %s" % entry_point .name )
125+ # except DependencyConflictError as exc:
126+ # print(
127+ # "Skipping instrumentation %s: %s" % (
128+ # entry_point.name,
129+ # exc.conflict,
130+ # )
131+ # )
132+ # _logger.debug(
133+ # "Skipping instrumentation %s: %s",
134+ # entry_point.name,
135+ # exc.conflict,
136+ # )
137+ # continue
138+ # except ModuleNotFoundError as exc:
139+ # # ModuleNotFoundError is raised when the library is not installed
140+ # # and the instrumentation is not required to be loaded.
141+ # # See https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3421
142+ # print(
143+ # "Skipping instrumentation %s: %s" % (entry_point.name, exc.msg)
144+ # )
145+ # _logger.debug(
146+ # "Skipping instrumentation %s: %s", entry_point.name, exc.msg
147+ # )
148+ # continue
93149 except ImportError :
94150 # in scenarios using the kubernetes operator to do autoinstrumentation some
95151 # instrumentors (usually requiring binary extensions) may fail to load
96152 # because the injected autoinstrumentation code does not match the application
97153 # environment regarding python version, libc, etc... In this case it's better
98154 # to skip the single instrumentation rather than failing to load everything
99155 # so treat differently ImportError than the rest of exceptions
156+ print (
157+ "Skipping instrumentation %s: ImportError" % entry_point .name
158+ )
100159 _logger .exception (
101160 "Importing of %s failed, skipping it" , entry_point .name
102161 )
103162 continue
104163 except Exception as exc : # pylint: disable=broad-except
164+ print (
165+ "Skipping instrumentation %s: %s" % (entry_point .name , exc )
166+ )
105167 _logger .exception ("Instrumenting of %s failed" , entry_point .name )
106168 raise exc
107169
0 commit comments