Skip to content

Commit c5b5b7c

Browse files
authored
Fix live metrics race condition (#45944)
* Fix live metrics race condition * format
1 parent b87ae34 commit c5b5b7c

File tree

1 file changed

+70
-40
lines changed
  • sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/quickpulse

1 file changed

+70
-40
lines changed

sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/quickpulse/QuickPulseDataCollector.java

Lines changed: 70 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
import java.util.concurrent.atomic.AtomicInteger;
4545
import java.util.concurrent.atomic.AtomicLong;
4646
import java.util.concurrent.atomic.AtomicReference;
47+
import java.util.concurrent.locks.ReadWriteLock;
48+
import java.util.concurrent.locks.ReentrantReadWriteLock;
4749
import java.util.function.Supplier;
4850

4951
final class QuickPulseDataCollector {
@@ -56,6 +58,9 @@ final class QuickPulseDataCollector {
5658
private final CpuPerformanceCounterCalculator cpuPerformanceCounterCalculator
5759
= getCpuPerformanceCounterCalculator();
5860

61+
// used to prevent race condition between processing a telemetry item and reporting it to the Quick Pulse service
62+
private final ReadWriteLock lock = new ReentrantReadWriteLock();
63+
5964
private volatile QuickPulseStatus quickPulseStatus = QuickPulseStatus.QP_IS_OFF;
6065

6166
private volatile Supplier<String> instrumentationKeySupplier;
@@ -91,25 +96,35 @@ synchronized QuickPulseStatus getQuickPulseStatus() {
9196
}
9297

9398
@Nullable
94-
synchronized FinalCounters getAndRestart() {
95-
FilteringConfiguration config = configuration.get();
96-
Counters currentCounters
97-
= counters.getAndSet(new Counters(config.getValidProjectionInitInfo(), config.getErrors()));
98-
if (currentCounters != null) {
99-
return new FinalCounters(currentCounters);
100-
}
99+
FinalCounters getAndRestart() {
100+
lock.writeLock().lock();
101+
try {
102+
FilteringConfiguration config = configuration.get();
103+
Counters currentCounters
104+
= counters.getAndSet(new Counters(config.getValidProjectionInitInfo(), config.getErrors()));
105+
if (currentCounters != null) {
106+
return new FinalCounters(currentCounters);
107+
}
101108

102-
return null;
109+
return null;
110+
} finally {
111+
lock.writeLock().unlock();
112+
}
103113
}
104114

105115
// only used by tests
106116
@Nullable
107-
synchronized FinalCounters peek() {
108-
Counters currentCounters = this.counters.get(); // this should be the only differece
109-
if (currentCounters != null) {
110-
return new FinalCounters(currentCounters);
117+
FinalCounters peek() {
118+
lock.readLock().lock();
119+
try {
120+
Counters currentCounters = this.counters.get(); // this should be the only differece
121+
if (currentCounters != null) {
122+
return new FinalCounters(currentCounters);
123+
}
124+
return null;
125+
} finally {
126+
lock.readLock().unlock();
111127
}
112-
return null;
113128
}
114129

115130
void add(TelemetryItem telemetryItem) {
@@ -130,15 +145,39 @@ void add(TelemetryItem telemetryItem) {
130145
int itemCount = sampleRate == null ? 1 : Math.round(100 / sampleRate);
131146
FilteringConfiguration currentConfig = configuration.get();
132147
MonitorDomain data = telemetryItem.getData().getBaseData();
133-
if (data instanceof RequestData) {
134-
RequestData requestTelemetry = (RequestData) data;
135-
addRequest(requestTelemetry, itemCount, getOperationName(telemetryItem), currentConfig);
136-
} else if (data instanceof RemoteDependencyData) {
137-
addDependency((RemoteDependencyData) data, itemCount, currentConfig);
138-
} else if (data instanceof TelemetryExceptionData) {
139-
addException((TelemetryExceptionData) data, itemCount, currentConfig);
140-
} else if (data instanceof MessageData) {
141-
addTrace((MessageData) data, currentConfig);
148+
149+
if (!(data instanceof RequestData)
150+
&& !(data instanceof RemoteDependencyData)
151+
&& !(data instanceof TelemetryExceptionData)
152+
&& !(data instanceof MessageData)) {
153+
// optimization before acquiring lock
154+
return;
155+
}
156+
157+
Counters counters = this.counters.get();
158+
if (counters == null) {
159+
// optimization before acquiring lock
160+
return;
161+
}
162+
163+
lock.readLock().lock();
164+
try {
165+
counters = this.counters.get();
166+
if (counters == null) {
167+
return;
168+
}
169+
if (data instanceof RequestData) {
170+
RequestData requestTelemetry = (RequestData) data;
171+
addRequest(requestTelemetry, itemCount, getOperationName(telemetryItem), currentConfig, counters);
172+
} else if (data instanceof RemoteDependencyData) {
173+
addDependency((RemoteDependencyData) data, itemCount, currentConfig, counters);
174+
} else if (data instanceof TelemetryExceptionData) {
175+
addException((TelemetryExceptionData) data, itemCount, currentConfig, counters);
176+
} else if (data instanceof MessageData) {
177+
addTrace((MessageData) data, currentConfig, counters);
178+
}
179+
} finally {
180+
lock.readLock().unlock();
142181
}
143182
}
144183

@@ -188,11 +227,9 @@ private void applyMetricFilters(TelemetryColumns columns, TelemetryType telemetr
188227
}
189228
}
190229

191-
private void addDependency(RemoteDependencyData telemetry, int itemCount, FilteringConfiguration currentConfig) {
192-
Counters counters = this.counters.get();
193-
if (counters == null) {
194-
return;
195-
}
230+
private void addDependency(RemoteDependencyData telemetry, int itemCount, FilteringConfiguration currentConfig,
231+
Counters counters) {
232+
196233
long durationMillis = parseDurationToMillis(telemetry.getDuration());
197234
counters.rddsAndDuations.addAndGet(Counters.encodeCountAndDuration(itemCount, durationMillis));
198235
Boolean success = telemetry.isSuccess();
@@ -221,12 +258,8 @@ private void addDependency(RemoteDependencyData telemetry, int itemCount, Filter
221258
}
222259
}
223260

224-
private void addException(TelemetryExceptionData exceptionData, int itemCount,
225-
FilteringConfiguration currentConfig) {
226-
Counters counters = this.counters.get();
227-
if (counters == null) {
228-
return;
229-
}
261+
private void addException(TelemetryExceptionData exceptionData, int itemCount, FilteringConfiguration currentConfig,
262+
Counters counters) {
230263

231264
counters.exceptions.addAndGet(itemCount);
232265

@@ -256,11 +289,8 @@ private void addException(TelemetryExceptionData exceptionData, int itemCount,
256289
}
257290

258291
private void addRequest(RequestData requestTelemetry, int itemCount, String operationName,
259-
FilteringConfiguration currentConfig) {
260-
Counters counters = this.counters.get();
261-
if (counters == null) {
262-
return;
263-
}
292+
FilteringConfiguration currentConfig, Counters counters) {
293+
264294
long durationMillis = parseDurationToMillis(requestTelemetry.getDuration());
265295
counters.requestsAndDurations.addAndGet(Counters.encodeCountAndDuration(itemCount, durationMillis));
266296
if (!requestTelemetry.isSuccess()) {
@@ -289,8 +319,8 @@ private void addRequest(RequestData requestTelemetry, int itemCount, String oper
289319
}
290320
}
291321

292-
private void addTrace(MessageData traceTelemetry, FilteringConfiguration currentConfig) {
293-
Counters counters = this.counters.get();
322+
private void addTrace(MessageData traceTelemetry, FilteringConfiguration currentConfig, Counters counters) {
323+
294324
TraceDataColumns columns = new TraceDataColumns(traceTelemetry);
295325
applyMetricFilters(columns, TelemetryType.TRACE, currentConfig, counters);
296326
List<String> documentStreamIds = new ArrayList<>();

0 commit comments

Comments
 (0)