Move metrics package to org.springframework.core
See gh-24878
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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 org.springframework.core.metrics;
|
||||
|
||||
/**
|
||||
* Instruments the application startup phase using {@link StartupStep steps}.
|
||||
* <p>The core container and its infrastructure components can use the {@code ApplicationStartup}
|
||||
* to mark steps during the application startup and collect data about the execution context
|
||||
* or their processing time.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 5.3
|
||||
*/
|
||||
public interface ApplicationStartup {
|
||||
|
||||
/**
|
||||
* Return a default "no op" {@code ApplicationStartup} implementation.
|
||||
* <p>This variant is designed for minimal overhead and does not record data.
|
||||
*/
|
||||
static ApplicationStartup getDefault() {
|
||||
return new DefaultApplicationStartup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new step and marks its beginning.
|
||||
* <p>A step name describes the current action or phase. This technical
|
||||
* name should be "." namespaced and can be reused to describe other instances of
|
||||
* the same step during application startup.
|
||||
* @param name the step name
|
||||
*/
|
||||
StartupStep start(String name);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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 org.springframework.core.metrics;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Default "no op" {@code ApplicationStartup} implementation.
|
||||
*
|
||||
* <p>This variant is designed for minimal overhead and does not record events.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class DefaultApplicationStartup implements ApplicationStartup {
|
||||
|
||||
@Override
|
||||
public DefaultStartupStep start(String name) {
|
||||
return new DefaultStartupStep();
|
||||
}
|
||||
|
||||
|
||||
static class DefaultStartupStep implements StartupStep {
|
||||
|
||||
boolean recorded = false;
|
||||
|
||||
private final DefaultTags TAGS = new DefaultTags();
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "default";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getParentId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tags tags() {
|
||||
return this.TAGS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StartupStep tag(String key, String value) {
|
||||
if (this.recorded) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StartupStep tag(String key, Supplier<String> value) {
|
||||
if (this.recorded) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
this.recorded = true;
|
||||
}
|
||||
|
||||
|
||||
static class DefaultTags implements StartupStep.Tags {
|
||||
|
||||
@Override
|
||||
public Iterator<StartupStep.Tag> iterator() {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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 org.springframework.core.metrics;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Step recording metrics about a particular phase or action happening during the {@link ApplicationStartup}.
|
||||
*
|
||||
* <p>The lifecycle of a {@code StartupStep} goes as follows:
|
||||
* <ol>
|
||||
* <li>the step is created and starts by calling {@link ApplicationStartup#start(String) the application startup}
|
||||
* and is assigned a unique {@link StartupStep#getId() id}.
|
||||
* <li>we can then attach information with {@link Tags} during processing
|
||||
* <li>we then need to mark the {@link #end()} of the step
|
||||
* </ol>
|
||||
*
|
||||
* <p>Implementations can track the "execution time" or other metrics for steps.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 5.3
|
||||
*/
|
||||
public interface StartupStep {
|
||||
|
||||
/**
|
||||
* Return the name of the startup step.
|
||||
* <p>A step name describes the current action or phase. This technical
|
||||
* name should be "." namespaced and can be reused to describe other instances of
|
||||
* similar steps during application startup.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the unique id for this step within the application startup.
|
||||
*/
|
||||
long getId();
|
||||
|
||||
/**
|
||||
* Return, if available, the id of the parent step.
|
||||
* <p>The parent step is the step that was started the most recently
|
||||
* when the current step was created.
|
||||
*/
|
||||
@Nullable
|
||||
Long getParentId();
|
||||
|
||||
/**
|
||||
* Add a {@link Tag} to the step.
|
||||
* @param key tag key
|
||||
* @param value tag value
|
||||
*/
|
||||
StartupStep tag(String key, String value);
|
||||
|
||||
/**
|
||||
* Add a {@link Tag} to the step.
|
||||
* @param key tag key
|
||||
* @param value {@link Supplier} for the tag value
|
||||
*/
|
||||
StartupStep tag(String key, Supplier<String> value);
|
||||
|
||||
/**
|
||||
* Return the {@link Tag} collection for this step.
|
||||
*/
|
||||
Tags tags();
|
||||
|
||||
/**
|
||||
* Record the state of the step and possibly other metrics like execution time.
|
||||
* <p>Once ended, changes on the step state are not allowed.
|
||||
*/
|
||||
void end();
|
||||
|
||||
|
||||
/**
|
||||
* Mutable collection of {@link Tag}.
|
||||
*/
|
||||
interface Tags extends Iterable<Tag> {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple key/value association for storing step metadata.
|
||||
*/
|
||||
interface Tag {
|
||||
|
||||
/**
|
||||
* Return the {@code Tag} name.
|
||||
*/
|
||||
String getKey();
|
||||
|
||||
/**
|
||||
* Return the {@code Tag} value.
|
||||
*/
|
||||
String getValue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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 org.springframework.core.metrics.jfr;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
import org.springframework.core.metrics.ApplicationStartup;
|
||||
import org.springframework.core.metrics.StartupStep;
|
||||
|
||||
/**
|
||||
* {@link ApplicationStartup} implementation for the Java Flight Recorder.
|
||||
* <p>This variant records {@link StartupStep} as Flight Recorder events; because such events
|
||||
* only support base types, the {@link StartupStep.Tags} are serialized as a single String attribute.
|
||||
* <p>Once this is configured on the application context, you can record data by launching the application
|
||||
* with recording enabled: {@code java -XX:StartFlightRecording:filename=recording.jfr,duration=10s -jar app.jar}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 5.3
|
||||
*/
|
||||
public class FlightRecorderApplicationStartup implements ApplicationStartup {
|
||||
|
||||
private long currentSequenceId;
|
||||
|
||||
private final Deque<Long> currentSteps;
|
||||
|
||||
|
||||
public FlightRecorderApplicationStartup() {
|
||||
this.currentSequenceId = 0;
|
||||
this.currentSteps = new ArrayDeque<>();
|
||||
this.currentSteps.offerFirst(0L);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public StartupStep start(String name) {
|
||||
FlightRecorderStartupStep step = new FlightRecorderStartupStep(++this.currentSequenceId, name,
|
||||
this.currentSteps.getFirst(), committedStep -> this.currentSteps.removeFirst());
|
||||
this.currentSteps.offerFirst(this.currentSequenceId);
|
||||
return step;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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 org.springframework.core.metrics.jfr;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.Label;
|
||||
|
||||
/**
|
||||
* {@link Event} extension for recording {@link FlightRecorderStartupStep}
|
||||
* in Java Flight Recorder.
|
||||
*
|
||||
* <p>{@link org.springframework.core.metrics.StartupStep.Tags} are serialized
|
||||
* as a single {@code String}, since Flight Recorder events do not support complex types.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 5.3
|
||||
*/
|
||||
@Category("Spring Application")
|
||||
@Label("Startup Step")
|
||||
@Description("Spring Application Startup")
|
||||
class FlightRecorderStartupEvent extends Event {
|
||||
|
||||
public final long eventId;
|
||||
|
||||
public final long parentId;
|
||||
|
||||
@Label("Name")
|
||||
public final String name;
|
||||
|
||||
@Label("Tags")
|
||||
String tags = "";
|
||||
|
||||
public FlightRecorderStartupEvent(long eventId, String name, long parentId) {
|
||||
this.name = name;
|
||||
this.eventId = eventId;
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public void setTags(String tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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 org.springframework.core.metrics.jfr;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.springframework.core.metrics.StartupStep;
|
||||
|
||||
/**
|
||||
* {@link StartupStep} implementation for the Java Flight Recorder.
|
||||
* <p>This variant delegates to a {@link FlightRecorderStartupEvent JFR event extension}
|
||||
* to collect and record data in Java Flight Recorder.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class FlightRecorderStartupStep implements StartupStep {
|
||||
|
||||
private final FlightRecorderStartupEvent event;
|
||||
|
||||
private final FlightRecorderTags tags = new FlightRecorderTags();
|
||||
|
||||
private final Consumer<FlightRecorderStartupStep> recordingCallback;
|
||||
|
||||
|
||||
public FlightRecorderStartupStep(long id, String name, long parentId,
|
||||
Consumer<FlightRecorderStartupStep> recordingCallback) {
|
||||
|
||||
this.event = new FlightRecorderStartupEvent(id, name, parentId);
|
||||
this.event.begin();
|
||||
this.recordingCallback = recordingCallback;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.event.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return this.event.eventId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getParentId() {
|
||||
return this.event.parentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StartupStep tag(String key, String value) {
|
||||
this.tags.add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StartupStep tag(String key, Supplier<String> value) {
|
||||
this.tags.add(key, value.get());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tags tags() {
|
||||
return this.tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
this.event.end();
|
||||
if (this.event.shouldCommit()) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
this.tags.forEach(tag ->
|
||||
builder.append(tag.getKey()).append('=').append(tag.getValue()).append(',')
|
||||
);
|
||||
this.event.setTags(builder.toString());
|
||||
}
|
||||
this.event.commit();
|
||||
this.recordingCallback.accept(this);
|
||||
}
|
||||
|
||||
protected FlightRecorderStartupEvent getEvent() {
|
||||
return this.event;
|
||||
}
|
||||
|
||||
|
||||
static class FlightRecorderTags implements Tags {
|
||||
|
||||
private Tag[] tags = new Tag[0];
|
||||
|
||||
public void add(String key, String value) {
|
||||
Tag[] newTags = new Tag[this.tags.length + 1];
|
||||
System.arraycopy(this.tags, 0, newTags, 0, this.tags.length);
|
||||
newTags[newTags.length - 1] = new FlightRecorderTag(key, value);
|
||||
this.tags = newTags;
|
||||
}
|
||||
|
||||
public void add(String key, Supplier<String> value) {
|
||||
add(key, value.get());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<Tag> iterator() {
|
||||
return new TagsIterator();
|
||||
}
|
||||
|
||||
private class TagsIterator implements Iterator<Tag> {
|
||||
|
||||
private int idx = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.idx < tags.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag next() {
|
||||
return tags[this.idx++];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("tags are append only");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class FlightRecorderTag implements Tag {
|
||||
|
||||
private final String key;
|
||||
|
||||
private final String value;
|
||||
|
||||
public FlightRecorderTag(String key, String value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Support package for recording startup metrics using Java Flight Recorder.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.core.metrics.jfr;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Support package for recording metrics during application startup.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.core.metrics;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
Reference in New Issue
Block a user