Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Universal profiling integration: Add stacktrace-IDs to transactions #3615

Merged
merged 10 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apm-agent-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
<dependency>
<groupId>co.elastic.otel</groupId>
<artifactId>jvmti-access</artifactId>
<version>0.3.0</version>
<version>0.3.1</version>
</dependency>
<!--
We can't use caffeine due to requiring Java 7.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,26 @@ public class UniversalProfilingConfiguration extends ConfigurationOptionProvider

private final ConfigurationOption<Boolean> enabled = ConfigurationOption.booleanOption()
.key("universal_profiling_integration_enabled")
.tags("added[1.50.0]", "internal")
.tags("added[1.50.0]")
.configurationCategory(PROFILING_CATEGORY)
.description("If enabled, the apm agent will correlate it's transaction with the profiling data from elastic universal profiling running on the same host.")
.buildWithDefault(false);

private final ConfigurationOption<Long> bufferSize = ConfigurationOption.longOption()
private final ConfigurationOption<Integer> bufferSize = ConfigurationOption.integerOption()
.key("universal_profiling_integration_buffer_size")
.addValidator(isInRange(64L, Long.MAX_VALUE))
.tags("added[1.50.0]", "internal")
.addValidator(isInRange(64, Integer.MAX_VALUE))
.tags("added[1.50.0]")
.configurationCategory(PROFILING_CATEGORY)
.description("The feature needs to buffer ended local-root spans for a short duration to ensure that all of its profiling data has been received." +
"This configuration option configures the buffer size in number of spans. " +
"The higher the number of local root spans per second, the higher this buffer size should be set.\n" +
"The agent will log a warning if it is not capable of buffering a span due to insufficient buffer size. " +
"This will cause the span to be exported immediately instead with possibly incomplete profiling correlation data.")
.buildWithDefault(4096L);
.buildWithDefault(4096);

private final ConfigurationOption<String> socketDir = ConfigurationOption.stringOption()
.key("universal_profiling_integration_socket_dir")
.tags("added[1.50.0]", "internal")
.tags("added[1.50.0]")
.configurationCategory(PROFILING_CATEGORY)
.description("The extension needs to bind a socket to a file for communicating with the universal profiling host agent." +
"This configuration option can be used to change the location. " +
Expand All @@ -60,7 +60,7 @@ public boolean isEnabled() {
return enabled.get();
}

public long getBufferSize() {
public int getBufferSize() {
return bufferSize.get();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,10 @@ public synchronized void stop() {
public Reporter getReporter() {
return reporter;
}

public UniversalProfilingIntegration getProfilingIntegration() {
return profilingIntegration;
}

public Sampler getSampler() {
return sampler;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package co.elastic.apm.agent.report.serialize;

import com.dslplatform.json.JsonWriter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package co.elastic.apm.agent.universalprofiling;

public interface Clock {

Clock SYSTEM_NANOTIME = new Clock() {
@Override
public long getNanos() {
return System.nanoTime();
}
};

long getNanos();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package co.elastic.apm.agent.universalprofiling;

public interface MoveableEvent<SELF extends MoveableEvent<?>> {

/**
* Moves the content from this event into the provided other event. This event should be in a
* resetted state after the call.
*/
void moveInto(SELF other);

void clear();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package co.elastic.apm.agent.universalprofiling;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.EventPoller;

import java.util.function.Supplier;

/**
* Wrapper around {@link EventPoller} which allows to "peek" elements. The provided event handling
* callback can decide to not handle an event. In that case, the event will be provided again as
* first element on the next call to {@link #poll(Handler)}.
*/
public class PeekingPoller<Event extends MoveableEvent<Event>> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class and the tests are a copy of https://github.com/elastic/elastic-otel-java/blob/main/universal-profiling-integration/src/main/java/co/elastic/otel/disruptor/PeekingPoller.java.

The only changes made are removal of Java-8 feature usages.


public interface Handler<Event extends MoveableEvent<Event>> {

/**
* Handles an event fetched from the ring buffer.
*
* @return true, if the event was handled and shall be removed. False if the event was not
* handled, no further invocations of handleEvent are desired and the same event shall be
* provided for the next {@link PeekingPoller#poll(Handler)} call.
*/
boolean handleEvent(Event e);
}

private final EventPoller<Event> poller;
private final Event peekedEvent;
private boolean peekedEventPopulated;

Handler<? super Event> currentHandler;
private final EventPoller.Handler<Event> subHandler = new EventPoller.Handler<Event>() {
@Override
public boolean onEvent(Event event, long sequence, boolean endOfBatch) throws Exception {
return handleEvent(event, sequence, endOfBatch);
}
};

public PeekingPoller(EventPoller<Event> wrappedPoller, EventFactory<Event> emptyEventFactory) {
this.poller = wrappedPoller;
peekedEvent = emptyEventFactory.newInstance();
peekedEventPopulated = false;
}

public synchronized void poll(Handler<? super Event> handler) throws Exception {
if (peekedEventPopulated) {
boolean handled = handler.handleEvent(peekedEvent);
if (!handled) {
return;
}
peekedEvent.clear();
peekedEventPopulated = false;
}
currentHandler = handler;
try {
poller.poll(subHandler);
} finally {
currentHandler = null;
}
}

private boolean handleEvent(Event event, long sequence, boolean endOfBatch) {
boolean handled = currentHandler.handleEvent(event);
if (handled) {
return true;
} else {
peekedEventPopulated = true;
event.moveInto(peekedEvent);
return false;
}
}
}
Loading
Loading