This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit 2dc16e182384438498781f94ea2580a32ca05ca0 Author: Claus Ibsen <[email protected]> AuthorDate: Tue Jan 19 19:49:19 2021 +0100 CAMEL-16056: Added StartupStep to diagnose startup exeuction times for various steps. --- .../main/java/org/apache/camel/StartupStep.java | 7 --- .../org/apache/camel/spi/StartupStepRecorder.java | 8 +-- .../camel/impl/engine/AbstractCamelContext.java | 8 ++- .../org/apache/camel/impl/DefaultCamelContext.java | 8 +++ .../MainConfigurationPropertiesConfigurer.java | 12 ++++ .../camel-main-configuration-metadata.json | 2 + core/camel-main/src/main/docs/main.adoc | 2 + .../camel/main/DefaultConfigurationConfigurer.java | 17 ++++++ .../camel/main/DefaultConfigurationProperties.java | 54 ++++++++++++++++++ .../support/{ => startup}/DefaultStartupStep.java | 6 +- .../{ => startup}/DefaultStartupStepRecorder.java | 37 ++----------- .../startup/LoggingStartupStepRecorder.java | 62 +++++++++++++++++++++ .../jfr/FlightRecorderStartupStep.java} | 64 ++++++++++++---------- .../jfr/FlightRecorderStartupStepRecorder.java | 40 ++++++++++++++ 14 files changed, 247 insertions(+), 80 deletions(-) diff --git a/core/camel-api/src/main/java/org/apache/camel/StartupStep.java b/core/camel-api/src/main/java/org/apache/camel/StartupStep.java index 18f23cd..58d7114 100644 --- a/core/camel-api/src/main/java/org/apache/camel/StartupStep.java +++ b/core/camel-api/src/main/java/org/apache/camel/StartupStep.java @@ -62,11 +62,4 @@ public interface StartupStep { */ long getBeginTime(); - /** - * Add metadata. - * - * @param key the key - * @param value the value - */ - void addTag(String key, String value); } diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/StartupStepRecorder.java b/core/camel-api/src/main/java/org/apache/camel/spi/StartupStepRecorder.java index 60df638..91296d6 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/StartupStepRecorder.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/StartupStepRecorder.java @@ -36,14 +36,14 @@ public interface StartupStepRecorder extends StaticService { void setEnabled(boolean enabled); /** - * Whether to automatic disable this recorder after Camel has been started. - * This is done by default to remove any overhead after the startup process is done. + * Whether to automatic disable this recorder after Camel has been started. This is done by default to remove any + * overhead after the startup process is done. */ boolean isDisableAfterStarted(); /** - * Whether to automatic disable this recorder after Camel has been started. - * This is done by default to remove any overhead after the startup process is done. + * Whether to automatic disable this recorder after Camel has been started. This is done by default to remove any + * overhead after the startup process is done. */ void setDisableAfterStarted(boolean disableAfterStarted); diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java index b4ccabd..8640bd7 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java @@ -154,7 +154,6 @@ import org.apache.camel.spi.Validator; import org.apache.camel.spi.ValidatorRegistry; import org.apache.camel.spi.XMLRoutesDefinitionLoader; import org.apache.camel.support.CamelContextHelper; -import org.apache.camel.support.DefaultStartupStepRecorder; import org.apache.camel.support.EndpointHelper; import org.apache.camel.support.EventHelper; import org.apache.camel.support.LRUCacheFactory; @@ -165,6 +164,7 @@ import org.apache.camel.support.ResolverHelper; import org.apache.camel.support.jsse.SSLContextParameters; import org.apache.camel.support.service.BaseService; import org.apache.camel.support.service.ServiceHelper; +import org.apache.camel.support.startup.DefaultStartupStepRecorder; import org.apache.camel.util.IOHelper; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.StopWatch; @@ -2527,6 +2527,9 @@ public abstract class AbstractCamelContext extends BaseService @Override public void doBuild() throws Exception { bootDate = System.currentTimeMillis(); + if (!(startupStepRecorder instanceof DefaultStartupStepRecorder)) { + LOG.info("Using startup recorder: {}", startupStepRecorder); + } startupStepRecorder.start(); StartupStep step = startupStepRecorder.beginStep(CamelContext.class, null, "Building context"); @@ -3249,6 +3252,8 @@ public abstract class AbstractCamelContext extends BaseService // start the route service routeServices.put(routeService.getId(), routeService); if (shouldStartRoutes()) { + StartupStep step + = startupStepRecorder.beginStep(Route.class, routeService.getId(), "Starting route services"); // this method will log the routes being started internalRouteStartupManager.safelyStartRouteServices(true, true, true, false, addingRoutes, routeService); // start route services if it was configured to auto startup @@ -3259,6 +3264,7 @@ public abstract class AbstractCamelContext extends BaseService // starting a route (not adding new routes) routeService.start(); } + startupStepRecorder.endStep(step); } } } finally { diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java index 43e4941..71ff083 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java @@ -24,10 +24,12 @@ import java.util.function.Function; import org.apache.camel.CamelContext; import org.apache.camel.Expression; +import org.apache.camel.ExtendedCamelContext; import org.apache.camel.FailedToStartRouteException; import org.apache.camel.Predicate; import org.apache.camel.Processor; import org.apache.camel.Route; +import org.apache.camel.StartupStep; import org.apache.camel.ValueHolder; import org.apache.camel.builder.AdviceWith; import org.apache.camel.builder.AdviceWithRouteBuilder; @@ -60,6 +62,7 @@ import org.apache.camel.spi.ExecutorServiceManager; import org.apache.camel.spi.ModelReifierFactory; import org.apache.camel.spi.PropertiesComponent; import org.apache.camel.spi.Registry; +import org.apache.camel.spi.StartupStepRecorder; import org.apache.camel.spi.Transformer; import org.apache.camel.spi.Validator; import org.apache.camel.support.CamelContextHelper; @@ -600,7 +603,12 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame routeDefinition.markPrepared(); } + StartupStepRecorder recorder + = getCamelContextReference().adapt(ExtendedCamelContext.class).getStartupStepRecorder(); + StartupStep step = recorder.beginStep(Route.class, routeDefinition.getRouteId(), "Creating route"); Route route = model.getModelReifierFactory().createRoute(this, routeDefinition); + recorder.endStep(step); + RouteService routeService = new RouteService(route); startRouteService(routeService, true); diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java index 28ced68..0ec603e 100644 --- a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java +++ b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java @@ -143,6 +143,10 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "ShutdownSuppressLoggingOnTimeout": target.setShutdownSuppressLoggingOnTimeout(property(camelContext, boolean.class, value)); return true; case "shutdowntimeout": case "ShutdownTimeout": target.setShutdownTimeout(property(camelContext, int.class, value)); return true; + case "startuprecorder": + case "StartupRecorder": target.setStartupRecorder(property(camelContext, java.lang.String.class, value)); return true; + case "startuprecordermaxdepth": + case "StartupRecorderMaxDepth": target.setStartupRecorderMaxDepth(property(camelContext, int.class, value)); return true; case "streamcachinganyspoolrules": case "StreamCachingAnySpoolRules": target.setStreamCachingAnySpoolRules(property(camelContext, boolean.class, value)); return true; case "streamcachingbuffersize": @@ -310,6 +314,10 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "ShutdownSuppressLoggingOnTimeout": return boolean.class; case "shutdowntimeout": case "ShutdownTimeout": return int.class; + case "startuprecorder": + case "StartupRecorder": return java.lang.String.class; + case "startuprecordermaxdepth": + case "StartupRecorderMaxDepth": return int.class; case "streamcachinganyspoolrules": case "StreamCachingAnySpoolRules": return boolean.class; case "streamcachingbuffersize": @@ -478,6 +486,10 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "ShutdownSuppressLoggingOnTimeout": return target.isShutdownSuppressLoggingOnTimeout(); case "shutdowntimeout": case "ShutdownTimeout": return target.getShutdownTimeout(); + case "startuprecorder": + case "StartupRecorder": return target.getStartupRecorder(); + case "startuprecordermaxdepth": + case "StartupRecorderMaxDepth": return target.getStartupRecorderMaxDepth(); case "streamcachinganyspoolrules": case "StreamCachingAnySpoolRules": return target.isStreamCachingAnySpoolRules(); case "streamcachingbuffersize": diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json index 7a249fd..9429f05 100644 --- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json +++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json @@ -71,6 +71,8 @@ { "name": "camel.main.shutdownRoutesInReverseOrder", "description": "Sets whether routes should be shutdown in reverse or the same order as they were started.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true }, { "name": "camel.main.shutdownSuppressLoggingOnTimeout", "description": "Whether Camel should try to suppress logging during shutdown and timeout was triggered, meaning forced shutdown is happening. And during forced shutdown we want to avoid logging errors\/warnings et all in the logs as a side-effect of the forced timeout. Notice the suppress is a best effort as there may still be some logs coming from 3rd party libraries and whatnot, which Camel cannot control. This option is defa [...] { "name": "camel.main.shutdownTimeout", "description": "Timeout in seconds to graceful shutdown Camel.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "int", "defaultValue": 45 }, + { "name": "camel.main.startupRecorder", "description": "To use startup recorder for capturing execution time during starting Camel. The recorder can be one of: false, logging, java-flight-recorder The default is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.main.startupRecorderMaxDepth", "description": "To filter our sub steps at a maximum depth. Use -1 for no maximum. Use 0 for no sub steps. Use 1 for max 1 sub step, and so forth. The default is -1.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "int", "defaultValue": -1 }, { "name": "camel.main.streamCachingAnySpoolRules", "description": "Sets whether if just any of the org.apache.camel.spi.StreamCachingStrategy.SpoolRule rules returns true then shouldSpoolCache(long) returns true, to allow spooling to disk. If this option is false, then all the org.apache.camel.spi.StreamCachingStrategy.SpoolRule must return true. The default value is false which means that all the rules must return true.", "sourceType": "org.apache.camel.main.DefaultConfigurationProp [...] { "name": "camel.main.streamCachingBufferSize", "description": "Sets the stream caching buffer size to use when allocating in-memory buffers used for in-memory stream caches. The default size is 4096.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "int" }, { "name": "camel.main.streamCachingEnabled", "description": "Sets whether stream caching is enabled or not. Default is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean" }, diff --git a/core/camel-main/src/main/docs/main.adoc b/core/camel-main/src/main/docs/main.adoc index 32177f1..7c60056 100644 --- a/core/camel-main/src/main/docs/main.adoc +++ b/core/camel-main/src/main/docs/main.adoc @@ -83,6 +83,8 @@ The following table lists all the options: | *camel.main.shutdownRoutesIn{zwsp}ReverseOrder* | Sets whether routes should be shutdown in reverse or the same order as they were started. | true | boolean | *camel.main.shutdownSuppress{zwsp}LoggingOnTimeout* | Whether Camel should try to suppress logging during shutdown and timeout was triggered, meaning forced shutdown is happening. And during forced shutdown we want to avoid logging errors/warnings et all in the logs as a side-effect of the forced timeout. Notice the suppress is a best effort as there may still be some logs coming from 3rd party libraries and whatnot, which Camel cannot control. This option is default false. | | boolean | *camel.main.shutdownTimeout* | Timeout in seconds to graceful shutdown Camel. | 45 | int +| *camel.main.startupRecorder* | To use startup recorder for capturing execution time during starting Camel. The recorder can be one of: false, logging, java-flight-recorder The default is false. | | String +| *camel.main.startupRecorderMax{zwsp}Depth* | To filter our sub steps at a maximum depth. Use -1 for no maximum. Use 0 for no sub steps. Use 1 for max 1 sub step, and so forth. The default is -1. | -1 | int | *camel.main.streamCachingAny{zwsp}SpoolRules* | Sets whether if just any of the org.apache.camel.spi.StreamCachingStrategy.SpoolRule rules returns true then shouldSpoolCache(long) returns true, to allow spooling to disk. If this option is false, then all the org.apache.camel.spi.StreamCachingStrategy.SpoolRule must return true. The default value is false which means that all the rules must return true. | | boolean | *camel.main.streamCachingBuffer{zwsp}Size* | Sets the stream caching buffer size to use when allocating in-memory buffers used for in-memory stream caches. The default size is 4096. | | int | *camel.main.streamCaching{zwsp}Enabled* | Sets whether stream caching is enabled or not. Default is false. | | boolean diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java index 51c200f..e8a2757 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java @@ -59,6 +59,7 @@ import org.apache.camel.spi.RouteController; import org.apache.camel.spi.RoutePolicyFactory; import org.apache.camel.spi.RuntimeEndpointRegistry; import org.apache.camel.spi.ShutdownStrategy; +import org.apache.camel.spi.StartupStepRecorder; import org.apache.camel.spi.StreamCachingStrategy; import org.apache.camel.spi.SupervisingRouteController; import org.apache.camel.spi.ThreadPoolFactory; @@ -66,6 +67,8 @@ import org.apache.camel.spi.ThreadPoolProfile; import org.apache.camel.spi.UnitOfWorkFactory; import org.apache.camel.spi.UuidGenerator; import org.apache.camel.support.jsse.GlobalSSLContextParametersSupplier; +import org.apache.camel.support.startup.LoggingStartupStepRecorder; +import org.apache.camel.support.startup.jfr.FlightRecorderStartupStepRecorder; import org.apache.camel.util.ObjectHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,6 +92,16 @@ public final class DefaultConfigurationConfigurer { */ public static void configure(CamelContext camelContext, DefaultConfigurationProperties config) throws Exception { ExtendedCamelContext ecc = camelContext.adapt(ExtendedCamelContext.class); + + if (config.getStartupRecorder() != null && !"false".equals(config.getStartupRecorder())) { + if ("logging".equals(config.getStartupRecorder())) { + ecc.setStartupStepRecorder(new LoggingStartupStepRecorder()); + } else if ("java-flight-recorder".equals(config.getStartupRecorder())) { + ecc.setStartupStepRecorder(new FlightRecorderStartupStepRecorder()); + } + } + ecc.getStartupStepRecorder().setMaxDepth(config.getStartupRecorderMaxDepth()); + ecc.setLightweight(config.isLightweight()); ecc.getBeanPostProcessor().setEnabled(config.isBeanPostProcessorEnabled()); ecc.getBeanIntrospection().setExtendedStatistics(config.isBeanIntrospectionExtendedStatistics()); @@ -239,6 +252,10 @@ public final class DefaultConfigurationConfigurer { final ManagementStrategy managementStrategy = camelContext.getManagementStrategy(); final ExtendedCamelContext ecc = camelContext.adapt(ExtendedCamelContext.class); + StartupStepRecorder ssr = getSingleBeanOfType(registry, StartupStepRecorder.class); + if (ssr != null) { + ecc.setStartupStepRecorder(ssr); + } PropertiesComponent pc = getSingleBeanOfType(registry, PropertiesComponent.class); if (pc != null) { ecc.setPropertiesComponent(pc); diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java index 44de80a..8b71105 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java @@ -100,6 +100,8 @@ public abstract class DefaultConfigurationProperties<T> { private long routeControllerBackOffMaxAttempts; private double routeControllerBackOffMultiplier; private boolean routeControllerUnhealthyOnExhausted; + private String startupRecorder; + private int startupRecorderMaxDepth = -1; // getter and setters // -------------------------------------------------------------- @@ -1096,6 +1098,35 @@ public abstract class DefaultConfigurationProperties<T> { this.routeControllerUnhealthyOnExhausted = routeControllerUnhealthyOnExhausted; } + public String getStartupRecorder() { + return startupRecorder; + } + + /** + * To use startup recorder for capturing execution time during starting Camel. The recorder can be one of: false, + * logging, java-flight-recorder + * + * The default is false. + */ + public void setStartupRecorder(String startupRecorder) { + this.startupRecorder = startupRecorder; + } + + public int getStartupRecorderMaxDepth() { + return startupRecorderMaxDepth; + } + + /** + * To filter our sub steps at a maximum depth. + * + * Use -1 for no maximum. Use 0 for no sub steps. Use 1 for max 1 sub step, and so forth. + * + * The default is -1. + */ + public void setStartupRecorderMaxDepth(int startupRecorderMaxDepth) { + this.startupRecorderMaxDepth = startupRecorderMaxDepth; + } + // fluent builders // -------------------------------------------------------------- @@ -1847,4 +1878,27 @@ public abstract class DefaultConfigurationProperties<T> { return (T) this; } + /** + * To use startup recorder for capturing execution time during starting Camel. The recorder can be one of: false, + * logging, java-flight-recorder + * + * The default is false. + */ + public T withStartupRecorder(String startupRecorder) { + this.startupRecorder = startupRecorder; + return (T) this; + } + + /** + * To filter our sub steps at a maximum depth. + * + * Use -1 for no maximum. Use 0 for no sub steps. Use 1 for max 1 sub step, and so forth. + * + * The default is -1. + */ + public T withStartupRecorderMaxDepth(int startupRecorderMaxDepth) { + this.startupRecorderMaxDepth = startupRecorderMaxDepth; + return (T) this; + } + } diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultStartupStep.java b/core/camel-support/src/main/java/org/apache/camel/support/startup/DefaultStartupStep.java similarity index 95% copy from core/camel-support/src/main/java/org/apache/camel/support/DefaultStartupStep.java copy to core/camel-support/src/main/java/org/apache/camel/support/startup/DefaultStartupStep.java index c8e9e46..d604743 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultStartupStep.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/startup/DefaultStartupStep.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.support; +package org.apache.camel.support.startup; import org.apache.camel.StartupStep; @@ -78,8 +78,4 @@ public class DefaultStartupStep implements StartupStep { // noop } - @Override - public void addTag(String key, String value) { - - } } diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultStartupStepRecorder.java b/core/camel-support/src/main/java/org/apache/camel/support/startup/DefaultStartupStepRecorder.java similarity index 77% rename from core/camel-support/src/main/java/org/apache/camel/support/DefaultStartupStepRecorder.java rename to core/camel-support/src/main/java/org/apache/camel/support/startup/DefaultStartupStepRecorder.java index e07e1ce..0fab31e 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultStartupStepRecorder.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/startup/DefaultStartupStepRecorder.java @@ -14,28 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.support; +package org.apache.camel.support.startup; import java.util.ArrayDeque; -import java.util.Arrays; import java.util.Deque; import java.util.concurrent.atomic.AtomicInteger; import org.apache.camel.StartupStep; import org.apache.camel.spi.StartupStepRecorder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** - * Default {@link StartupStepRecorder} that outputs to log. + * Default {@link StartupStepRecorder} that is always disabled. */ public class DefaultStartupStepRecorder implements StartupStepRecorder { - private static final Logger LOG = LoggerFactory.getLogger(StartupStepRecorder.class); - - // TODO: jfr implementation - // TODO: spring-boot implementation - private final AtomicInteger stepCounter = new AtomicInteger(); private final Deque<Integer> currentSteps = new ArrayDeque<>(); @@ -80,13 +72,10 @@ public class DefaultStartupStepRecorder implements StartupStepRecorder { return 0; } - @Override - public void addTag(String key, String value) { - // noop - } }; public DefaultStartupStepRecorder() { + currentSteps.offerFirst(0); } private boolean enabled; @@ -165,25 +154,7 @@ public class DefaultStartupStepRecorder implements StartupStepRecorder { } protected void onEndStep(StartupStep step) { - if (LOG.isInfoEnabled()) { - long delta = System.currentTimeMillis() - step.getBeginTime(); - String pad = padString(step.getLevel()); - String out = String.format("%s", pad + step.getType()); - String out2 = String.format("%6s ms", delta); - String out3 = String.format("%s(%s)", step.getDescription(), step.getName()); - LOG.info("{} : {} - {}", out2, out, out3); - } - } - - public static String padString(int level) { - if (level == 0) { - return ""; - } else { - byte[] arr = new byte[level * 2]; - byte space = ' '; - Arrays.fill(arr, space); - return new String(arr); - } + // noop } } diff --git a/core/camel-support/src/main/java/org/apache/camel/support/startup/LoggingStartupStepRecorder.java b/core/camel-support/src/main/java/org/apache/camel/support/startup/LoggingStartupStepRecorder.java new file mode 100644 index 0000000..3c73db0 --- /dev/null +++ b/core/camel-support/src/main/java/org/apache/camel/support/startup/LoggingStartupStepRecorder.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.camel.support.startup; + +import java.util.Arrays; + +import org.apache.camel.StartupStep; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Logging {@link org.apache.camel.spi.StartupStepRecorder} that outputs to log. + */ +public class LoggingStartupStepRecorder extends DefaultStartupStepRecorder { + + private static final Logger LOG = LoggerFactory.getLogger(LoggingStartupStepRecorder.class); + + public LoggingStartupStepRecorder() { + setEnabled(true); + } + + protected void onEndStep(StartupStep step) { + if (LOG.isInfoEnabled()) { + long delta = System.currentTimeMillis() - step.getBeginTime(); + String pad = padString(step.getLevel()); + String out = String.format("%s", pad + step.getType()); + String out2 = String.format("%6s ms", delta); + String out3 = String.format("%s(%s)", step.getDescription(), step.getName()); + LOG.info("{} : {} - {}", out2, out, out3); + } + } + + public static String padString(int level) { + if (level == 0) { + return ""; + } else { + byte[] arr = new byte[level * 2]; + byte space = ' '; + Arrays.fill(arr, space); + return new String(arr); + } + } + + @Override + public String toString() { + return "logging"; + } +} diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultStartupStep.java b/core/camel-support/src/main/java/org/apache/camel/support/startup/jfr/FlightRecorderStartupStep.java similarity index 60% rename from core/camel-support/src/main/java/org/apache/camel/support/DefaultStartupStep.java rename to core/camel-support/src/main/java/org/apache/camel/support/startup/jfr/FlightRecorderStartupStep.java index c8e9e46..f07b712 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultStartupStep.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/startup/jfr/FlightRecorderStartupStep.java @@ -14,33 +14,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.support; +package org.apache.camel.support.startup.jfr; +import jdk.jfr.Category; +import jdk.jfr.Description; +import jdk.jfr.Event; +import jdk.jfr.Label; +import jdk.jfr.Name; +import jdk.jfr.StackTrace; import org.apache.camel.StartupStep; -public class DefaultStartupStep implements StartupStep { +@Name(FlightRecorderStartupStep.NAME) +@Category("Camel Application") +@Label("Startup Step") +@Description("Camel Application Startup") +@StackTrace(false) +public class FlightRecorderStartupStep extends Event implements StartupStep { - private final String type; - private final String name; - private final String description; - private final int id; - private final int parentId; - private final int level; - private final long time; + public static final String NAME = "org.apache.camel.spi.CamelEvent"; - public DefaultStartupStep(String type, String name, String description, int id, int parentId, int level, long time) { - this.type = type; + @Label("Event Name") + public final String name; + @Label("Event Id") + public final int id; + @Label("Event Parent Id") + public final int parentId; + @Label("Event Type") + public String type; + @Label("Event Description") + public String description; + + public FlightRecorderStartupStep(String name, int id, int parentId) { this.name = name; - this.description = description; this.id = id; this.parentId = parentId; - this.level = level; - this.time = time; - } - - @Override - public String getType() { - return type; } @Override @@ -49,11 +56,6 @@ public class DefaultStartupStep implements StartupStep { } @Override - public String getDescription() { - return description; - } - - @Override public int getId() { return id; } @@ -65,21 +67,23 @@ public class DefaultStartupStep implements StartupStep { @Override public int getLevel() { - return level; + // not used by jfr + return 0; } @Override public long getBeginTime() { - return time; + // not used by jfr + return 0; } @Override - public void end() { - // noop + public String getType() { + return type; } @Override - public void addTag(String key, String value) { - + public String getDescription() { + return description; } } diff --git a/core/camel-support/src/main/java/org/apache/camel/support/startup/jfr/FlightRecorderStartupStepRecorder.java b/core/camel-support/src/main/java/org/apache/camel/support/startup/jfr/FlightRecorderStartupStepRecorder.java new file mode 100644 index 0000000..7c216ac --- /dev/null +++ b/core/camel-support/src/main/java/org/apache/camel/support/startup/jfr/FlightRecorderStartupStepRecorder.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.camel.support.startup.jfr; + +import org.apache.camel.StartupStep; +import org.apache.camel.support.startup.DefaultStartupStepRecorder; + +/** + * To capture startup steps to be emitted to Java Flight Recorder. + */ +public class FlightRecorderStartupStepRecorder extends DefaultStartupStepRecorder { + + public FlightRecorderStartupStepRecorder() { + setEnabled(true); + } + + @Override + public StartupStep createStartupStep(String type, String name, String description, int id, int parentId, int level) { + return new FlightRecorderStartupStep(name, id, parentId); + } + + @Override + public String toString() { + return "java-flight-recorder"; + } +}
