This is an automated email from the ASF dual-hosted git repository. kezhenxu94 pushed a commit to branch event/jvm in repository https://gitbox.apache.org/repos/asf/skywalking.git
commit dc5c2dabd6381d2c06684b08bc20742b9ff8ab03 Author: kezhenxu94 <[email protected]> AuthorDate: Tue Mar 16 20:36:25 2021 +0800 Collect and report agent starting / shutdown events --- ...tService.java => ServiceInstanceGenerator.java} | 31 ++-- .../apm/agent/core/boot/BootService.java | 9 + .../apm/agent/core/boot/ServiceManager.java | 4 +- .../core/remote/EventReportServiceClient.java | 190 +++++++++++++++++++++ .../apm/agent/core/remote/GRPCChannelManager.java | 5 + .../agent/core/remote/ServiceManagementClient.java | 8 +- ...ache.skywalking.apm.agent.core.boot.BootService | 3 +- .../skywalking/oap/server/core/event/Event.java | 2 +- 8 files changed, 233 insertions(+), 19 deletions(-) diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/BootService.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/ServiceInstanceGenerator.java similarity index 52% copy from apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/BootService.java copy to apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/ServiceInstanceGenerator.java index eae8a5c..eff46e7 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/BootService.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/ServiceInstanceGenerator.java @@ -16,18 +16,29 @@ * */ -package org.apache.skywalking.apm.agent.core.boot; +package org.apache.skywalking.apm.agent.core; -/** - * The <code>BootService</code> is an interface to all remote, which need to boot when plugin mechanism begins to work. - * {@link #boot()} will be called when <code>BootService</code> start up. - */ -public interface BootService { - void prepare() throws Throwable; +import java.util.UUID; +import lombok.Getter; +import lombok.experimental.Accessors; +import org.apache.skywalking.apm.agent.core.conf.Config; +import org.apache.skywalking.apm.agent.core.os.OSUtil; + +import static org.apache.skywalking.apm.util.StringUtil.isEmpty; + +@Getter +@Accessors(fluent = true) +public enum ServiceInstanceGenerator { + SINGLETON; - void boot() throws Throwable; + private boolean isGenerated = false; - void onComplete() throws Throwable; + public synchronized void generateIfNotSpecified() { + if (!isEmpty(Config.Agent.INSTANCE_NAME)) { + return; + } - void shutdown() throws Throwable; + Config.Agent.INSTANCE_NAME = UUID.randomUUID().toString().replaceAll("-", "") + "@" + OSUtil.getIPV4(); + isGenerated = true; + } } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/BootService.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/BootService.java index eae8a5c..4907866 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/BootService.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/BootService.java @@ -18,6 +18,8 @@ package org.apache.skywalking.apm.agent.core.boot; +import org.apache.skywalking.apm.agent.core.remote.GRPCChannelManager; + /** * The <code>BootService</code> is an interface to all remote, which need to boot when plugin mechanism begins to work. * {@link #boot()} will be called when <code>BootService</code> start up. @@ -30,4 +32,11 @@ public interface BootService { void onComplete() throws Throwable; void shutdown() throws Throwable; + + /** + * @return the shutdown order that {@link ServiceManager} should respect to when shutting down the services, e.g. services depending on {@link GRPCChannelManager} should be shut down after it. + */ + default int shutdownOrder() { + return 0; + } } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/ServiceManager.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/ServiceManager.java index 46158cd..b2e9bdc 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/ServiceManager.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/ServiceManager.java @@ -19,11 +19,13 @@ package org.apache.skywalking.apm.agent.core.boot; import java.util.Collections; +import java.util.Comparator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.ServiceLoader; +import java.util.stream.Collectors; import org.apache.skywalking.apm.agent.core.logging.api.ILog; import org.apache.skywalking.apm.agent.core.logging.api.LogManager; import org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader; @@ -46,7 +48,7 @@ public enum ServiceManager { } public void shutdown() { - for (BootService service : bootedServices.values()) { + for (BootService service : bootedServices.values().stream().sorted(Comparator.comparing(BootService::shutdownOrder)).collect(Collectors.toList())) { try { service.shutdown(); } catch (Throwable e) { diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/remote/EventReportServiceClient.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/remote/EventReportServiceClient.java new file mode 100644 index 0000000..cad9ad3 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/remote/EventReportServiceClient.java @@ -0,0 +1,190 @@ +/* + * 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.skywalking.apm.agent.core.remote; + +import io.grpc.stub.StreamObserver; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; +import org.apache.skywalking.apm.agent.core.ServiceInstanceGenerator; +import org.apache.skywalking.apm.agent.core.boot.BootService; +import org.apache.skywalking.apm.agent.core.boot.DefaultImplementor; +import org.apache.skywalking.apm.agent.core.boot.ServiceManager; +import org.apache.skywalking.apm.agent.core.commands.CommandService; +import org.apache.skywalking.apm.agent.core.conf.Config; +import org.apache.skywalking.apm.agent.core.logging.api.ILog; +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; +import org.apache.skywalking.apm.network.common.v3.Commands; +import org.apache.skywalking.apm.network.event.v3.Event; +import org.apache.skywalking.apm.network.event.v3.EventServiceGrpc; +import org.apache.skywalking.apm.network.event.v3.Source; +import org.apache.skywalking.apm.network.event.v3.Type; + +import static org.apache.skywalking.apm.agent.core.remote.GRPCChannelStatus.CONNECTED; + +@DefaultImplementor +public class EventReportServiceClient implements BootService, GRPCChannelListener { + private static final ILog LOGGER = LogManager.getLogger(EventReportServiceClient.class); + + private final AtomicBoolean reported = new AtomicBoolean(); + + private Event.Builder startingEvent; + + private EventServiceGrpc.EventServiceStub eventServiceStub; + + private GRPCChannelStatus status; + + @Override + public void prepare() throws Throwable { + ServiceManager.INSTANCE.findService(GRPCChannelManager.class).addChannelListener(this); + ServiceInstanceGenerator.SINGLETON.generateIfNotSpecified(); + + if (ServiceInstanceGenerator.SINGLETON.isGenerated()) { + LOGGER.debug("The service instance is generated, no starting event will be reported"); + return; + } + + final RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); + startingEvent = Event.newBuilder() + .setUuid(UUID.randomUUID().toString()) + .setName("Start") + .setStartTime(runtimeMxBean.getStartTime()) + .setMessage("Start Java Application") + .setType(Type.Normal) + .setSource( + Source.newBuilder() + .setService(Config.Agent.SERVICE_NAME) + .setServiceInstance(Config.Agent.INSTANCE_NAME) + .build() + ) + .putParameters( + "OPTS", + runtimeMxBean.getInputArguments() + .stream() + .sorted() + .collect(Collectors.joining(" ")) + ); + } + + @Override + public void boot() throws Throwable { + + } + + @Override + public void onComplete() throws Throwable { + reportStartingEvent(); + } + + @Override + public void shutdown() throws Throwable { + if (ServiceInstanceGenerator.SINGLETON.isGenerated()) { + // If the agent service instance name is randomly generated, ignore the shutdown signal. + return; + } + + if (!CONNECTED.equals(status)) { + return; + } + + final CountDownLatch latch = new CountDownLatch(1); + final Event.Builder shutdownEvent = Event.newBuilder() + .setUuid(UUID.randomUUID().toString()) + .setName("Shutdown") + .setStartTime(System.currentTimeMillis()) + .setEndTime(System.currentTimeMillis()) + .setMessage("Shutting down Java Application") + .setType(Type.Normal) + .setSource( + Source.newBuilder() + .setService(Config.Agent.SERVICE_NAME) + .setServiceInstance(Config.Agent.INSTANCE_NAME) + .build() + ); + + final StreamObserver<Event> collector = eventServiceStub.collect(new StreamObserver<Commands>() { + @Override + public void onNext(final Commands commands) { + ServiceManager.INSTANCE.findService(CommandService.class).receiveCommand(commands); + } + + @Override + public void onError(final Throwable t) { + LOGGER.error("Failed to report shutdown event.", t); + // Ignore status change at shutting down stage. + latch.countDown(); + } + + @Override + public void onCompleted() { + latch.countDown(); + } + }); + + collector.onNext(shutdownEvent.build()); + collector.onCompleted(); + latch.await(); + } + + @Override + public void statusChanged(final GRPCChannelStatus status) { + this.status = status; + + if (!CONNECTED.equals(status)) { + return; + } + + eventServiceStub = EventServiceGrpc.newStub(ServiceManager.INSTANCE.findService(GRPCChannelManager.class).getChannel()); + + reportStartingEvent(); + } + + private void reportStartingEvent() { + if (ServiceInstanceGenerator.SINGLETON.isGenerated() || reported.compareAndSet(false, true)) { + return; + } + + startingEvent.setEndTime(System.currentTimeMillis()); + + final StreamObserver<Event> collector = eventServiceStub.collect(new StreamObserver<Commands>() { + @Override + public void onNext(final Commands commands) { + ServiceManager.INSTANCE.findService(CommandService.class).receiveCommand(commands); + } + + @Override + public void onError(final Throwable t) { + LOGGER.error("Failed to report starting event.", t); + ServiceManager.INSTANCE.findService(GRPCChannelManager.class).reportError(t); + reported.set(false); + + } + + @Override + public void onCompleted() { + } + }); + + collector.onNext(startingEvent.build()); + collector.onCompleted(); + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/remote/GRPCChannelManager.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/remote/GRPCChannelManager.java index 4822c75..5a2ffb0 100755 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/remote/GRPCChannelManager.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/remote/GRPCChannelManager.java @@ -208,4 +208,9 @@ public class GRPCChannelManager implements BootService, Runnable { } return false; } + + @Override + public int shutdownOrder() { + return Integer.MAX_VALUE; + } } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/remote/ServiceManagementClient.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/remote/ServiceManagementClient.java index f271856..3d5437f 100755 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/remote/ServiceManagementClient.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/remote/ServiceManagementClient.java @@ -21,11 +21,11 @@ package org.apache.skywalking.apm.agent.core.remote; import io.grpc.Channel; import java.util.ArrayList; import java.util.List; -import java.util.UUID; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import org.apache.skywalking.apm.agent.core.ServiceInstanceGenerator; import org.apache.skywalking.apm.agent.core.boot.BootService; import org.apache.skywalking.apm.agent.core.boot.DefaultImplementor; import org.apache.skywalking.apm.agent.core.boot.DefaultNamedThreadFactory; @@ -41,7 +41,6 @@ import org.apache.skywalking.apm.network.management.v3.InstancePingPkg; import org.apache.skywalking.apm.network.management.v3.InstanceProperties; import org.apache.skywalking.apm.network.management.v3.ManagementServiceGrpc; import org.apache.skywalking.apm.util.RunnableWithExceptionProtection; -import org.apache.skywalking.apm.util.StringUtil; import static org.apache.skywalking.apm.agent.core.conf.Config.Collector.GRPC_UPSTREAM_TIMEOUT; @@ -69,6 +68,7 @@ public class ServiceManagementClient implements BootService, Runnable, GRPCChann @Override public void prepare() { ServiceManager.INSTANCE.findService(GRPCChannelManager.class).addChannelListener(this); + ServiceInstanceGenerator.SINGLETON.generateIfNotSpecified(); SERVICE_INSTANCE_PROPERTIES = new ArrayList<>(); @@ -78,10 +78,6 @@ public class ServiceManagementClient implements BootService, Runnable, GRPCChann .setValue(Config.Agent.INSTANCE_PROPERTIES.get(key)) .build()); } - - Config.Agent.INSTANCE_NAME = StringUtil.isEmpty(Config.Agent.INSTANCE_NAME) - ? UUID.randomUUID().toString().replaceAll("-", "") + "@" + OSUtil.getIPV4() - : Config.Agent.INSTANCE_NAME; } @Override diff --git a/apm-sniffer/apm-agent-core/src/main/resources/META-INF/services/org.apache.skywalking.apm.agent.core.boot.BootService b/apm-sniffer/apm-agent-core/src/main/resources/META-INF/services/org.apache.skywalking.apm.agent.core.boot.BootService index bfa58a8..5b9d995 100644 --- a/apm-sniffer/apm-agent-core/src/main/resources/META-INF/services/org.apache.skywalking.apm.agent.core.boot.BootService +++ b/apm-sniffer/apm-agent-core/src/main/resources/META-INF/services/org.apache.skywalking.apm.agent.core.boot.BootService @@ -33,4 +33,5 @@ org.apache.skywalking.apm.agent.core.meter.MeterService org.apache.skywalking.apm.agent.core.meter.MeterSender org.apache.skywalking.apm.agent.core.context.status.StatusCheckService org.apache.skywalking.apm.agent.core.remote.LogReportServiceClient -org.apache.skywalking.apm.agent.core.conf.dynamic.ConfigurationDiscoveryService \ No newline at end of file +org.apache.skywalking.apm.agent.core.conf.dynamic.ConfigurationDiscoveryService +org.apache.skywalking.apm.agent.core.remote.EventReportServiceClient diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/event/Event.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/event/Event.java index 8fb26d0..7065589 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/event/Event.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/event/Event.java @@ -95,7 +95,7 @@ public class Event extends Metrics { @Column(columnName = MESSAGE) private String message; - @Column(columnName = PARAMETERS, storageOnly = true) + @Column(columnName = PARAMETERS, storageOnly = true, length = 1024) private String parameters; @Column(columnName = START_TIME)
