55
66package io .opentelemetry .sdk .autoconfigure ;
77
8+ import static java .util .Objects .requireNonNull ;
9+
810import io .opentelemetry .api .incubator .config .ConfigProvider ;
911import io .opentelemetry .api .incubator .config .DeclarativeConfigException ;
1012import io .opentelemetry .api .incubator .config .GlobalConfigProvider ;
1820import java .io .InputStream ;
1921import java .lang .reflect .InvocationTargetException ;
2022import java .lang .reflect .Method ;
21- import java .util .Objects ;
2223import java .util .logging .Logger ;
24+ import javax .annotation .Nullable ;
2325
2426/**
2527 * Utilities for interacting with incubating components ({@code
@@ -32,54 +34,111 @@ final class IncubatingUtil {
3234
3335 private IncubatingUtil () {}
3436
37+ // Visible for testing
38+ interface Factory {
39+ @ Nullable
40+ AutoConfiguredOpenTelemetrySdk create ()
41+ throws ClassNotFoundException ,
42+ NoSuchMethodException ,
43+ IllegalAccessException ,
44+ InvocationTargetException ;
45+ }
46+
3547 static AutoConfiguredOpenTelemetrySdk configureFromFile (
3648 Logger logger , String configurationFile , ComponentLoader componentLoader ) {
3749 logger .fine ("Autoconfiguring from configuration file: " + configurationFile );
3850 try (FileInputStream fis = new FileInputStream (configurationFile )) {
39- Class <?> declarativeConfiguration =
40- Class .forName (
41- "io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration" );
42- Method parse = declarativeConfiguration .getMethod ("parse" , InputStream .class );
43- Object model = parse .invoke (null , fis );
44- Class <?> openTelemetryConfiguration =
45- Class .forName (
46- "io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel" );
47- Method create =
48- declarativeConfiguration .getMethod (
49- "create" , openTelemetryConfiguration , ComponentLoader .class );
50- OpenTelemetrySdk sdk = (OpenTelemetrySdk ) create .invoke (null , model , componentLoader );
51- Class <?> sdkConfigProvider =
52- Class .forName ("io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider" );
53- Method createFileConfigProvider =
54- sdkConfigProvider .getMethod ("create" , openTelemetryConfiguration , ComponentLoader .class );
55- ConfigProvider configProvider =
56- (ConfigProvider ) createFileConfigProvider .invoke (null , model , componentLoader );
57- // Note: can't access file configuration resource without reflection so setting a dummy
58- // resource
59- return AutoConfiguredOpenTelemetrySdk .create (
60- sdk , Resource .getDefault (), null , configProvider );
51+ return requireNonNull (
52+ createWithFactory (
53+ "file" ,
54+ () ->
55+ getOpenTelemetrySdk (
56+ Class .forName (
57+ "io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration" )
58+ .getMethod ("parse" , InputStream .class )
59+ .invoke (null , fis ),
60+ componentLoader )));
6161 } catch (FileNotFoundException e ) {
6262 throw new ConfigurationException ("Configuration file not found" , e );
63+ } catch (IOException e ) {
64+ // IOException (other than FileNotFoundException which is caught above) is only thrown
65+ // above by FileInputStream.close()
66+ throw new ConfigurationException ("Error closing file" , e );
67+ }
68+ }
69+
70+ @ Nullable
71+ public static AutoConfiguredOpenTelemetrySdk configureFromSpi (ComponentLoader componentLoader ) {
72+ return createWithFactory (
73+ "SPI" ,
74+ () -> {
75+ Class <?> providerClass =
76+ Class .forName (
77+ "io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationProvider" );
78+ Method getConfigurationModel = providerClass .getMethod ("getConfigurationModel" );
79+
80+ for (Object configProvider : componentLoader .load (providerClass )) {
81+ Object model = getConfigurationModel .invoke (configProvider );
82+ if (model != null ) {
83+ return getOpenTelemetrySdk (model , componentLoader );
84+ }
85+ }
86+ return null ;
87+ });
88+ }
89+
90+ private static AutoConfiguredOpenTelemetrySdk getOpenTelemetrySdk (
91+ Object model , ComponentLoader componentLoader )
92+ throws IllegalAccessException ,
93+ InvocationTargetException ,
94+ ClassNotFoundException ,
95+ NoSuchMethodException {
96+
97+ Class <?> openTelemetryConfiguration =
98+ Class .forName (
99+ "io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel" );
100+ Class <?> declarativeConfiguration =
101+ Class .forName (
102+ "io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration" );
103+ Method create =
104+ declarativeConfiguration .getMethod (
105+ "create" , openTelemetryConfiguration , ComponentLoader .class );
106+
107+ OpenTelemetrySdk sdk = (OpenTelemetrySdk ) create .invoke (null , model , componentLoader );
108+ Class <?> sdkConfigProvider =
109+ Class .forName ("io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider" );
110+ Method createFileConfigProvider =
111+ sdkConfigProvider .getMethod ("create" , openTelemetryConfiguration , ComponentLoader .class );
112+ ConfigProvider configProvider =
113+ (ConfigProvider ) createFileConfigProvider .invoke (null , model , componentLoader );
114+ // Note: can't access file configuration resource without reflection so setting a dummy
115+ // resource
116+ return AutoConfiguredOpenTelemetrySdk .create (sdk , Resource .getDefault (), null , configProvider );
117+ }
118+
119+ // Visible for testing
120+ @ Nullable
121+ static AutoConfiguredOpenTelemetrySdk createWithFactory (String name , Factory factory ) {
122+ try {
123+ return factory .create ();
63124 } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e ) {
64125 throw new ConfigurationException (
65- "Error configuring from file. Is opentelemetry-sdk-extension-incubator on the classpath?" ,
126+ String .format (
127+ "Error configuring from %s. Is opentelemetry-sdk-extension-incubator on the classpath?" ,
128+ name ),
66129 e );
67130 } catch (InvocationTargetException e ) {
68131 Throwable cause = e .getCause ();
69132 if (cause instanceof DeclarativeConfigException ) {
70133 throw toConfigurationException ((DeclarativeConfigException ) cause );
71134 }
72- throw new ConfigurationException ("Unexpected error configuring from file" , e );
73- } catch (IOException e ) {
74- // IOException (other than FileNotFoundException which is caught above) is only thrown
75- // above by FileInputStream.close()
76- throw new ConfigurationException ("Error closing file" , e );
135+ throw new ConfigurationException ("Unexpected error configuring from " + name , e );
77136 }
78137 }
79138
80139 private static ConfigurationException toConfigurationException (
81140 DeclarativeConfigException exception ) {
82- String message = Objects . requireNonNull (exception .getMessage ());
141+ String message = requireNonNull (exception .getMessage ());
83142 return new ConfigurationException (message , exception );
84143 }
85144
0 commit comments