Skip to content

Commit f487f6c

Browse files
authored
fix: ensure default telemetry attributes are sent (#145)
* fix: ensure default telemetry attributes are sent * fix configuration, don't send non-configured metrics, tests * create default config in Metrics * null metrics indicate nothing sent
1 parent de4e783 commit f487f6c

File tree

8 files changed

+209
-22
lines changed

8 files changed

+209
-22
lines changed

src/main/java/dev/openfga/sdk/api/auth/OAuth2Client.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ public OAuth2Client(Configuration configuration, ApiClient apiClient) throws Fga
5050
this.config = new Configuration()
5151
.apiUrl(buildApiTokenIssuer(clientCredentials.getApiTokenIssuer()))
5252
.maxRetries(configuration.getMaxRetries())
53-
.minimumRetryDelay(configuration.getMinimumRetryDelay());
53+
.minimumRetryDelay(configuration.getMinimumRetryDelay())
54+
.telemetryConfiguration(configuration.getTelemetryConfiguration());
5455
this.telemetry = new Telemetry(this.config);
5556
}
5657

src/main/java/dev/openfga/sdk/api/configuration/ClientConfiguration.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,10 @@ public ClientConfiguration minimumRetryDelay(Duration minimumRetryDelay) {
134134
super.minimumRetryDelay(minimumRetryDelay);
135135
return this;
136136
}
137+
138+
@Override
139+
public ClientConfiguration telemetryConfiguration(TelemetryConfiguration telemetryConfiguration) {
140+
super.telemetryConfiguration(telemetryConfiguration);
141+
return this;
142+
}
137143
}

src/main/java/dev/openfga/sdk/api/configuration/TelemetryConfiguration.java

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,64 @@
99
import java.util.Map;
1010
import java.util.Optional;
1111

12+
/**
13+
* Configures the telemetry settings for the SDK.
14+
*/
1215
public class TelemetryConfiguration {
1316
private Map<Metric, Map<Attribute, Optional<Object>>> metrics = new HashMap<>();
1417

15-
public TelemetryConfiguration() {
16-
Map<Attribute, Optional<Object>> defaultAttributes = new HashMap<>();
17-
defaultAttributes.put(Attributes.FGA_CLIENT_REQUEST_CLIENT_ID, Optional.empty());
18-
defaultAttributes.put(Attributes.FGA_CLIENT_REQUEST_METHOD, Optional.empty());
19-
defaultAttributes.put(Attributes.FGA_CLIENT_REQUEST_MODEL_ID, Optional.empty());
20-
defaultAttributes.put(Attributes.FGA_CLIENT_REQUEST_STORE_ID, Optional.empty());
21-
defaultAttributes.put(Attributes.FGA_CLIENT_RESPONSE_MODEL_ID, Optional.empty());
22-
defaultAttributes.put(Attributes.HTTP_HOST, Optional.empty());
23-
defaultAttributes.put(Attributes.HTTP_REQUEST_METHOD, Optional.empty());
24-
defaultAttributes.put(Attributes.HTTP_REQUEST_RESEND_COUNT, Optional.empty());
25-
defaultAttributes.put(Attributes.HTTP_RESPONSE_STATUS_CODE, Optional.empty());
26-
defaultAttributes.put(Attributes.URL_FULL, Optional.empty());
27-
defaultAttributes.put(Attributes.URL_SCHEME, Optional.empty());
28-
defaultAttributes.put(Attributes.USER_AGENT, Optional.empty());
18+
private static final Map<Attribute, Optional<Object>> defaultAttributes = Map.ofEntries(
19+
Map.entry(Attributes.FGA_CLIENT_REQUEST_CLIENT_ID, Optional.empty()),
20+
Map.entry(Attributes.FGA_CLIENT_REQUEST_METHOD, Optional.empty()),
21+
Map.entry(Attributes.FGA_CLIENT_REQUEST_MODEL_ID, Optional.empty()),
22+
Map.entry(Attributes.FGA_CLIENT_REQUEST_STORE_ID, Optional.empty()),
23+
Map.entry(Attributes.FGA_CLIENT_RESPONSE_MODEL_ID, Optional.empty()),
24+
Map.entry(Attributes.HTTP_HOST, Optional.empty()),
25+
Map.entry(Attributes.HTTP_REQUEST_METHOD, Optional.empty()),
26+
Map.entry(Attributes.HTTP_REQUEST_RESEND_COUNT, Optional.empty()),
27+
Map.entry(Attributes.HTTP_RESPONSE_STATUS_CODE, Optional.empty()),
28+
Map.entry(Attributes.URL_FULL, Optional.empty()),
29+
Map.entry(Attributes.URL_SCHEME, Optional.empty()),
30+
Map.entry(Attributes.USER_AGENT, Optional.empty()));
2931

32+
/**
33+
* Constructs a TelemetryConfiguration object with the the metrics and attributes to send by default.
34+
*/
35+
public TelemetryConfiguration() {
3036
metrics.put(Counters.CREDENTIALS_REQUEST, defaultAttributes);
3137
metrics.put(Histograms.QUERY_DURATION, defaultAttributes);
3238
metrics.put(Histograms.REQUEST_DURATION, defaultAttributes);
3339
}
3440

41+
/**
42+
* Constructs a TelemetryConfiguration object with the specified metrics.
43+
* @param metrics the metrics to send
44+
*/
45+
public TelemetryConfiguration(Map<Metric, Map<Attribute, Optional<Object>>> metrics) {
46+
this.metrics = metrics;
47+
}
48+
49+
/**
50+
* Sets the metrics to send.
51+
* @param metrics the metrics to send
52+
* @return this TelemetryConfiguration object
53+
*/
3554
public TelemetryConfiguration metrics(Map<Metric, Map<Attribute, Optional<Object>>> metrics) {
3655
this.metrics = metrics;
3756
return this;
3857
}
3958

59+
/**
60+
* @return the metrics to send.
61+
*/
4062
public Map<Metric, Map<Attribute, Optional<Object>>> metrics() {
4163
return metrics;
4264
}
65+
66+
/**
67+
* @return the default attributes to send.
68+
*/
69+
public static Map<Attribute, Optional<Object>> defaultAttributes() {
70+
return defaultAttributes;
71+
}
4372
}

src/main/java/dev/openfga/sdk/telemetry/Metrics.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.openfga.sdk.telemetry;
22

33
import dev.openfga.sdk.api.configuration.Configuration;
4+
import dev.openfga.sdk.api.configuration.TelemetryConfiguration;
45
import io.opentelemetry.api.OpenTelemetry;
56
import io.opentelemetry.api.metrics.DoubleHistogram;
67
import io.opentelemetry.api.metrics.LongCounter;
@@ -23,13 +24,17 @@ public Metrics() {
2324
this.counters = new HashMap<>();
2425
this.histograms = new HashMap<>();
2526
this.configuration = new Configuration();
27+
this.configuration.telemetryConfiguration(new TelemetryConfiguration());
2628
}
2729

2830
public Metrics(Configuration configuration) {
2931
this.meter = OpenTelemetry.noop().getMeterProvider().get("openfga-sdk");
3032
this.counters = new HashMap<>();
3133
this.histograms = new HashMap<>();
3234
this.configuration = configuration;
35+
if (this.configuration.getTelemetryConfiguration() == null) {
36+
this.configuration.telemetryConfiguration(new TelemetryConfiguration());
37+
}
3338
}
3439

3540
/**
@@ -48,9 +53,13 @@ public Meter getMeter() {
4853
* @param value The value to be added to the counter.
4954
* @param attributes A map of attributes associated with the metric.
5055
*
51-
* @return The LongCounter metric instance.
56+
* @return The LongCounter metric instance, if the counter was configured. Otherwise, null.
5257
*/
5358
public LongCounter getCounter(Counter counter, Long value, Map<Attribute, String> attributes) {
59+
if (configuration.getTelemetryConfiguration().metrics() == null
60+
|| !configuration.getTelemetryConfiguration().metrics().containsKey(counter)) {
61+
return null;
62+
}
5463
if (!counters.containsKey(counter.getName())) {
5564
counters.put(
5665
counter.getName(),
@@ -74,8 +83,15 @@ public LongCounter getCounter(Counter counter, Long value, Map<Attribute, String
7483
* @param histogram The Histogram enum representing the metric.
7584
* @param value The value to be recorded in the histogram.
7685
* @param attributes A map of attributes associated with the metric.
86+
*
87+
* @return the DoubleHistogram instance, if the histogram was configured. Otherwise, null.
7788
*/
7889
public DoubleHistogram getHistogram(Histogram histogram, Double value, Map<Attribute, String> attributes) {
90+
if (configuration.getTelemetryConfiguration().metrics() == null
91+
|| !configuration.getTelemetryConfiguration().metrics().containsKey(histogram)) {
92+
return null;
93+
}
94+
7995
if (!histograms.containsKey(histogram.getName())) {
8096
histograms.put(
8197
histogram.getName(),

src/main/java/dev/openfga/sdk/telemetry/Telemetry.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* The Telemetry class provides access to telemetry-related functionality.
77
*/
88
public class Telemetry {
9-
private Configuration configuration = new Configuration();
9+
private Configuration configuration = null;
1010
private Metrics metrics = null;
1111

1212
public Telemetry(Configuration configuration) {

src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public class OpenFgaApiTest {
4747
private static final String EMPTY_RESPONSE_BODY = "{}";
4848
private static final int DEFAULT_MAX_RETRIES = 3;
4949
private static final Duration DEFAULT_RETRY_DELAY = Duration.ofMillis(100);
50+
private static final TelemetryConfiguration DEFAULT_TELEMETRY_CONFIG = new TelemetryConfiguration();
5051

5152
private final ObjectMapper mapper = new ObjectMapper();
5253
private OpenFgaApi fga;
@@ -72,6 +73,7 @@ public void beforeEachTest() throws Exception {
7273
when(mockConfiguration.getCredentials()).thenReturn(new Credentials());
7374
when(mockConfiguration.getMaxRetries()).thenReturn(DEFAULT_MAX_RETRIES);
7475
when(mockConfiguration.getMinimumRetryDelay()).thenReturn(DEFAULT_RETRY_DELAY);
76+
when(mockConfiguration.getTelemetryConfiguration()).thenReturn(DEFAULT_TELEMETRY_CONFIG);
7577

7678
mockApiClient = mock(ApiClient.class);
7779
when(mockApiClient.getObjectMapper()).thenReturn(mapper);

src/test/java/dev/openfga/sdk/telemetry/AttributesTest.java

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,16 @@ void testPrepare() {
2424
// Arrange
2525
Map<Attribute, String> attributes = new HashMap<>();
2626
attributes.put(Attributes.FGA_CLIENT_REQUEST_CLIENT_ID, "client-id-value");
27-
Metric metric = mock(Metric.class);
27+
Metric metric = Histograms.QUERY_DURATION;
2828

29-
TelemetryConfiguration telemetryConfiguration = mock(TelemetryConfiguration.class);
3029
Map<Metric, Map<Attribute, Optional<Object>>> metricsMap = new HashMap<>();
3130
Map<Attribute, Optional<Object>> attributeMap = new HashMap<>();
3231
attributeMap.put(Attributes.FGA_CLIENT_REQUEST_CLIENT_ID, Optional.of("config-value"));
3332
metricsMap.put(metric, attributeMap);
34-
when(telemetryConfiguration.metrics()).thenReturn(metricsMap);
33+
TelemetryConfiguration telemetryConfiguration = new TelemetryConfiguration(metricsMap);
3534

36-
Configuration configuration = mock(Configuration.class);
37-
when(configuration.getTelemetryConfiguration()).thenReturn(telemetryConfiguration);
35+
Configuration configuration = new Configuration();
36+
configuration.telemetryConfiguration(telemetryConfiguration);
3837

3938
// Act
4039
io.opentelemetry.api.common.Attributes result = Attributes.prepare(attributes, metric, configuration);
@@ -47,6 +46,43 @@ void testPrepare() {
4746
assertEquals(expected, result);
4847
}
4948

49+
@Test
50+
void testPrepare_filtersAttributesFromDefaults() {
51+
// Arrange
52+
53+
// sent by default
54+
Map<Attribute, String> defaultAttributes = new HashMap<>();
55+
for (Map.Entry<Attribute, Optional<Object>> entry :
56+
TelemetryConfiguration.defaultAttributes().entrySet()) {
57+
defaultAttributes.put(entry.getKey(), entry.getKey().toString() + "-value");
58+
}
59+
60+
// not sent by default
61+
Map<Attribute, String> nonDefaultAttributes = new HashMap<>();
62+
nonDefaultAttributes.put(Attributes.FGA_CLIENT_USER, "user-value");
63+
64+
Map<Attribute, String> attributes = new HashMap<>();
65+
attributes.putAll(defaultAttributes);
66+
attributes.putAll(nonDefaultAttributes);
67+
68+
Metric metric = Histograms.QUERY_DURATION;
69+
70+
Configuration configuration = new Configuration();
71+
configuration.telemetryConfiguration(new TelemetryConfiguration());
72+
73+
// Act
74+
io.opentelemetry.api.common.Attributes result = Attributes.prepare(attributes, metric, configuration);
75+
76+
// Assert
77+
AttributesBuilder builder = io.opentelemetry.api.common.Attributes.builder();
78+
for (Map.Entry<Attribute, String> entry : defaultAttributes.entrySet()) {
79+
builder.put(AttributeKey.stringKey(entry.getKey().getName()), entry.getValue());
80+
}
81+
io.opentelemetry.api.common.Attributes expected = builder.build();
82+
83+
assertEquals(expected, result);
84+
}
85+
5086
@Test
5187
void testFromHttpResponse() {
5288
// Arrange

src/test/java/dev/openfga/sdk/telemetry/MetricsTest.java

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
import static org.junit.jupiter.api.Assertions.*;
44
import static org.mockito.Mockito.mock;
5+
import static org.mockito.Mockito.when;
56

67
import dev.openfga.sdk.api.configuration.Configuration;
8+
import dev.openfga.sdk.api.configuration.TelemetryConfiguration;
79
import io.opentelemetry.api.metrics.DoubleHistogram;
810
import io.opentelemetry.api.metrics.LongCounter;
911
import io.opentelemetry.api.metrics.Meter;
1012
import java.util.HashMap;
1113
import java.util.Map;
14+
import java.util.Optional;
1215
import org.junit.jupiter.api.BeforeEach;
1316
import org.junit.jupiter.api.Test;
1417

@@ -21,6 +24,8 @@ class MetricsTest {
2124
void setUp() {
2225
configuration = mock(Configuration.class);
2326
metrics = new Metrics(configuration);
27+
28+
when(configuration.getTelemetryConfiguration()).thenReturn(new TelemetryConfiguration());
2429
}
2530

2631
@Test
@@ -116,4 +121,96 @@ void testQueryDuration() {
116121
// Assert
117122
assertNotNull(doubleHistogram, "The DoubleHistogram object should not be null.");
118123
}
124+
125+
@Test
126+
void testMetricsNotSentIfNotConfigured() {
127+
Map<Attribute, Optional<Object>> attributes = new HashMap<>();
128+
attributes.put(Attributes.FGA_CLIENT_REQUEST_METHOD, Optional.empty());
129+
Map<Metric, Map<Attribute, Optional<Object>>> metrics = new HashMap<>();
130+
metrics.put(Histograms.QUERY_DURATION, attributes);
131+
TelemetryConfiguration telemetryConfiguration = new TelemetryConfiguration(metrics);
132+
133+
Configuration config = new Configuration();
134+
config.telemetryConfiguration(telemetryConfiguration);
135+
136+
Metrics configuredMetrics = new Metrics(config);
137+
138+
DoubleHistogram requestDuration =
139+
configuredMetrics.getHistogram(Histograms.REQUEST_DURATION, 10.0, new HashMap<>());
140+
assertNull(requestDuration, "Unconfigured histograms should not be sent.");
141+
142+
DoubleHistogram queryDuration =
143+
configuredMetrics.getHistogram(Histograms.QUERY_DURATION, 10.0, new HashMap<>());
144+
assertNotNull(queryDuration, "Configured histograms should be sent.");
145+
146+
LongCounter credsRequestCounter =
147+
configuredMetrics.getCounter(Counters.CREDENTIALS_REQUEST, 10L, new HashMap<>());
148+
assertNull(credsRequestCounter, "Unconfigured counters should not be sent.");
149+
}
150+
151+
@Test
152+
void testCountersNotSentIfNotConfigured() {
153+
Map<Attribute, Optional<Object>> attributes = new HashMap<>();
154+
attributes.put(Attributes.FGA_CLIENT_REQUEST_METHOD, Optional.empty());
155+
Map<Metric, Map<Attribute, Optional<Object>>> metrics = new HashMap<>();
156+
metrics.put(Counters.CREDENTIALS_REQUEST, attributes);
157+
TelemetryConfiguration telemetryConfiguration = new TelemetryConfiguration(metrics);
158+
159+
Configuration config = new Configuration();
160+
config.telemetryConfiguration(telemetryConfiguration);
161+
162+
Metrics configuredMetrics = new Metrics(config);
163+
164+
DoubleHistogram requestDuration =
165+
configuredMetrics.getHistogram(Histograms.REQUEST_DURATION, 10.0, new HashMap<>());
166+
assertNull(requestDuration, "Unconfigured histograms should not be sent.");
167+
168+
DoubleHistogram queryDuration =
169+
configuredMetrics.getHistogram(Histograms.QUERY_DURATION, 10.0, new HashMap<>());
170+
assertNull(queryDuration, "Unconfigured histograms should not be sent.");
171+
172+
LongCounter credsCounter = configuredMetrics.getCounter(Counters.CREDENTIALS_REQUEST, 10L, new HashMap<>());
173+
assertNotNull(credsCounter, "Configured counter should be sent.");
174+
}
175+
176+
@Test
177+
void testDefaultMetricsEnabled() {
178+
// Arrange
179+
Configuration config = new Configuration();
180+
181+
// Act
182+
Metrics metrics = new Metrics(config);
183+
184+
// Assert
185+
assertNotNull(
186+
metrics.getCounter(Counters.CREDENTIALS_REQUEST, 10L, new HashMap<>()), "The counter should be sent.");
187+
assertNotNull(
188+
metrics.getHistogram(Histograms.QUERY_DURATION, 10.0, new HashMap<>()),
189+
"The query duration histogram should be sent.");
190+
assertNotNull(
191+
metrics.getHistogram(Histograms.REQUEST_DURATION, 10.0, new HashMap<>()),
192+
"The request duration histogram should be sent.");
193+
}
194+
195+
@Test
196+
void testMetricsWithNullMetricsConfig() {
197+
// Arrange
198+
TelemetryConfiguration telemetryConfiguration = new TelemetryConfiguration(null);
199+
Configuration config = new Configuration();
200+
config.telemetryConfiguration(telemetryConfiguration);
201+
202+
// Act
203+
Metrics metrics = new Metrics(config);
204+
205+
// Assert
206+
assertNull(
207+
metrics.getCounter(Counters.CREDENTIALS_REQUEST, 10L, new HashMap<>()),
208+
"The counter should not be sent.");
209+
assertNull(
210+
metrics.getHistogram(Histograms.QUERY_DURATION, 10.0, new HashMap<>()),
211+
"The query duration histogram should not be sent.");
212+
assertNull(
213+
metrics.getHistogram(Histograms.REQUEST_DURATION, 10.0, new HashMap<>()),
214+
"The request duration histogram should not be sent.");
215+
}
119216
}

0 commit comments

Comments
 (0)