diff --git a/eden-components/eden-dependencies/pom.xml b/eden-components/eden-dependencies/pom.xml index da637347..811e2173 100644 --- a/eden-components/eden-dependencies/pom.xml +++ b/eden-components/eden-dependencies/pom.xml @@ -113,9 +113,9 @@ 8.0.32 3.1.1 3.42.0.0 - 3.5.6 - 2.0.3 - 2.1.1 + 3.5.16 + 2.1.2 + 2.1.4 3.5.7 5.3.1 1.2.4 @@ -888,6 +888,16 @@ arthas-spring-boot-starter ${arthas.version} + + com.taobao.arthas + arthas-spy + ${arthas.version} + + + com.taobao.arthas + arthas-agent-attach + ${arthas.version} + diff --git a/eden-components/eden-solutions/eden-distributed-uid/src/main/java/org/ylzl/eden/distributed/uid/integration/leaf/LeafSegmentGenerator.java b/eden-components/eden-solutions/eden-distributed-uid/src/main/java/org/ylzl/eden/distributed/uid/integration/leaf/LeafSegmentGenerator.java index 85a73ca7..6e7a229d 100644 --- a/eden-components/eden-solutions/eden-distributed-uid/src/main/java/org/ylzl/eden/distributed/uid/integration/leaf/LeafSegmentGenerator.java +++ b/eden-components/eden-solutions/eden-distributed-uid/src/main/java/org/ylzl/eden/distributed/uid/integration/leaf/LeafSegmentGenerator.java @@ -135,7 +135,7 @@ private SpringLiquibase buildLiquibase(DataSource dataSource) { } private void updateCacheFromDb() { - log.debug("Update cache from db"); + log.debug("Leaf update cache from db"); try { List dbTags = leafAllocDAO.getAllTags(); if (dbTags == null || dbTags.isEmpty()) { @@ -155,24 +155,24 @@ private void updateCacheFromDb() { segment.setMax(0); segment.setStep(0); cache.put(tag, buffer); - log.debug("Add tag {} from db to IdCache", tag); + log.debug("Leaf add tag {} from db to IdCache", tag); } for (String tag : dbTags) { removeTagsSet.remove(tag); } for (String tag : removeTagsSet) { cache.remove(tag); - log.debug("Remove tag {} from IdCache", tag); + log.debug("Leaf remove tag {} from IdCache", tag); } } catch (Exception e) { - log.warn("Update cache from db exception", e); + log.warn("Leaf update cache from db exception", e); } } private void updateCacheFromDbAtEveryMinute() { ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(r -> { Thread t = new Thread(r); - t.setName("check-idCache-thread"); + t.setName("leaf-check-id-cache-thread"); t.setDaemon(true); return t; }); @@ -229,9 +229,9 @@ private long getIdFromSegmentBuffer(final SegmentBuffer buffer) { try { updateSegmentFromDb(buffer.getKey(), next); updateOk = true; - log.info("Update segment {} from db {}", buffer.getKey(), next); + log.info("Leaf update segment {} from db {}", buffer.getKey(), next); } catch (Exception e) { - log.error("Update segment {} from db {} error", buffer.getKey(), e); + log.error("Leaf update segment {} from db {} error", buffer.getKey(), e); } finally { if (updateOk) { buffer.wLock().lock(); diff --git a/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/pom.xml b/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/pom.xml index 381bdb8c..27449b2d 100644 --- a/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/pom.xml +++ b/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/pom.xml @@ -55,5 +55,13 @@ com.taobao.arthas arthas-spring-boot-starter + + com.taobao.arthas + arthas-spy + + + com.taobao.arthas + arthas-agent-attach + diff --git a/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/src/main/java/org/ylzl/eden/arthas/spring/boot/attach/CustomArthasAgent.java b/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/src/main/java/org/ylzl/eden/arthas/spring/boot/attach/CustomArthasAgent.java new file mode 100644 index 00000000..adf01aad --- /dev/null +++ b/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/src/main/java/org/ylzl/eden/arthas/spring/boot/attach/CustomArthasAgent.java @@ -0,0 +1,155 @@ +package org.ylzl.eden.arthas.spring.boot.attach; + +import com.taobao.arthas.agent.attach.ArthasAgent; +import com.taobao.arthas.agent.attach.AttachArthasClassloader; +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.agent.ByteBuddyAgent; +import org.zeroturnaround.zip.ZipUtil; + +import java.arthas.SpyAPI; +import java.io.File; +import java.lang.instrument.Instrumentation; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +/** + * 自定义 ArthasAgent + * + * @author gyl + * @since 2.4.13 + */ +@Slf4j +public class CustomArthasAgent extends ArthasAgent { + + private static final int TEMP_DIR_ATTEMPTS = 10000; + + private static final String ARTHAS_CORE_JAR = "arthas-core.jar"; + private static final String ARTHAS_BOOTSTRAP = "com.taobao.arthas.core.server.ArthasBootstrap"; + private static final String GET_INSTANCE = "getInstance"; + private static final String IS_BIND = "isBind"; + + private static final Pattern ARTHAS_DIR_PATTERN = Pattern.compile("^arthas-(\\d{13})-.*$"); + private static final String ARTHAS_BIN_ZIP = "arthas-bin.zip"; + private static final String DESTROY = "destroy"; + + private String errorMessage; + + private Map configMap = new HashMap(); + private String arthasHome; + private boolean slientInit; + private Instrumentation instrumentation; + + private Class bootstrapClass; + private Object bootstrap; + + public CustomArthasAgent() { + this(null, null, false, null); + } + + public CustomArthasAgent(Map configMap) { + this(configMap, null, false, null); + } + + public CustomArthasAgent(String arthasHome) { + this(null, arthasHome, false, null); + } + + public CustomArthasAgent(Map configMap, String arthasHome, boolean slientInit, + Instrumentation instrumentation) { + if (configMap != null) { + this.configMap = configMap; + } + + this.arthasHome = arthasHome; + this.slientInit = slientInit; + this.instrumentation = instrumentation; + } + + public String getErrorMessage() { + return errorMessage; + } + + @Override + public void init() throws IllegalStateException { + // 尝试判断arthas是否已在运行,如果是的话,直接就退出 + try { + Class.forName("java.arthas.SpyAPI"); // 加载不到会抛异常 + if (SpyAPI.isInited()) { + return; + } + } catch (Throwable e) { + // ignore + } + + try { + if (instrumentation == null) { + instrumentation = ByteBuddyAgent.install(); + } + + // 检查 arthasHome + if (arthasHome == null || arthasHome.trim().isEmpty()) { + // 解压出 arthasHome + URL coreJarUrl = this.getClass().getClassLoader().getResource("arthas-bin.zip"); + if (coreJarUrl != null) { + File tempArthasDir = createTempDir(); + ZipUtil.unpack(coreJarUrl.openStream(), tempArthasDir); + arthasHome = tempArthasDir.getAbsolutePath(); + } else { + throw new IllegalArgumentException("can not getResources arthas-bin.zip from classloader: " + + this.getClass().getClassLoader()); + } + } + + // find arthas-core.jar + File arthasCoreJarFile = new File(arthasHome, ARTHAS_CORE_JAR); + if (!arthasCoreJarFile.exists()) { + throw new IllegalStateException("can not find arthas-core.jar under arthasHome: " + arthasHome); + } + AttachArthasClassloader arthasClassLoader = new AttachArthasClassloader( + new URL[] { arthasCoreJarFile.toURI().toURL() }); + + bootstrapClass = arthasClassLoader.loadClass(ARTHAS_BOOTSTRAP); + bootstrap = bootstrapClass.getMethod(GET_INSTANCE, Instrumentation.class, Map.class).invoke(null, + instrumentation, configMap); + boolean isBind = (Boolean) bootstrapClass.getMethod(IS_BIND).invoke(bootstrap); + if (!isBind) { + String errorMsg = "Arthas server port binding failed! Please check $HOME/logs/arthas/arthas.log for more details."; + throw new RuntimeException(errorMsg); + } + } catch (Throwable e) { + errorMessage = e.getMessage(); + if (!slientInit) { + throw new IllegalStateException(e); + } + } + } + + public void destroy() { + if (bootstrapClass == null) { + log.warn("Arthas is not already"); + return; + } + + try { + bootstrapClass.getMethod(DESTROY).invoke(bootstrap); + } catch (Throwable e) { + log.error(e.getMessage(), e); + } + } + + private static File createTempDir() { + File baseDir = new File(System.getProperty("java.io.tmpdir")); + String baseName = "arthas-" + System.currentTimeMillis() + "-"; + + for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) { + File tempDir = new File(baseDir, baseName + counter); + if (tempDir.mkdir()) { + return tempDir; + } + } + throw new IllegalStateException("Failed to create directory within " + TEMP_DIR_ATTEMPTS + " attempts (tried " + + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')'); + } +} diff --git a/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/src/main/java/org/ylzl/eden/arthas/spring/boot/autoconfigure/ArthasAutoConfiguration.java b/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/src/main/java/org/ylzl/eden/arthas/spring/boot/autoconfigure/ArthasAutoConfiguration.java index 87b62340..9cf7e108 100644 --- a/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/src/main/java/org/ylzl/eden/arthas/spring/boot/autoconfigure/ArthasAutoConfiguration.java +++ b/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/src/main/java/org/ylzl/eden/arthas/spring/boot/autoconfigure/ArthasAutoConfiguration.java @@ -20,15 +20,15 @@ import com.alibaba.arthas.spring.ArthasProperties; import com.alibaba.arthas.spring.StringUtils; import com.taobao.arthas.agent.attach.ArthasAgent; -import com.taobao.arthas.agent.attach.AttachArthasClassloader; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.agent.ByteBuddyAgent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; @@ -36,19 +36,12 @@ import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Role; import org.springframework.core.env.Environment; +import org.ylzl.eden.arthas.spring.boot.attach.CustomArthasAgent; import org.ylzl.eden.arthas.spring.boot.env.SpringArthasProperties; import org.ylzl.eden.spring.framework.bootstrap.constant.SpringProperties; -import java.io.File; -import java.lang.instrument.Instrumentation; -import java.net.URL; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.HashMap; +import java.util.Map; /** * Arthas 自动装配 @@ -56,12 +49,8 @@ * @author gyl * @since 2.4.13 */ -@ConditionalOnProperty( - name = {"spring.arthas.enabled"}, - matchIfMissing = true -) -@AutoConfigureAfter(ArthasConfiguration.class) -@EnableConfigurationProperties(SpringArthasProperties.class) +@AutoConfigureBefore(ArthasConfiguration.class) +@EnableConfigurationProperties({ SpringArthasProperties.class, ArthasProperties.class }) @RequiredArgsConstructor @Slf4j @Role(BeanDefinition.ROLE_INFRASTRUCTURE) @@ -76,20 +65,6 @@ public class ArthasAutoConfiguration { private static final String ARTHAS_AGENT_START_SUCCESS = "Arthas agent start success"; - private static final int TEMP_DIR_ATTEMPTS = 10000; - - private static final Pattern ARTHAS_DIR_PATTERN = Pattern.compile("^arthas-(\\d{13})-.*$"); - - private static final String ARTHAS_BIN_ZIP = "arthas-bin.zip"; - - private static final String ARTHAS_CORE_JAR = "arthas-core.jar"; - - private static final String ARTHAS_BOOTSTRAP = "com.taobao.arthas.core.server.ArthasBootstrap"; - - private static final String GET_INSTANCE = "getInstance"; - - private static final String DESTROY = "destroy"; - private final ApplicationContext applicationContext; private final Environment environment; @@ -103,6 +78,18 @@ public ArthasEnvironmentChangeListener arthasEnvironmentChangeListener( environment, arthasProperties, arthasConfigMap); } + @ConfigurationProperties(prefix = "arthas") + @ConditionalOnMissingBean(name = {"arthasConfigMap"}) + @Primary + @Bean + public HashMap arthasConfigMap() { + return new HashMap(); + } + + @ConditionalOnProperty( + name = {"spring.arthas.enabled"}, + matchIfMissing = true + ) @Primary @Bean public ArthasAgent arthasAgent(@Autowired @Qualifier(ARTHAS_CONFIG_MAP) Map arthasConfigMap) { @@ -112,6 +99,7 @@ public ArthasAgent arthasAgent(@Autowired @Qualifier(ARTHAS_CONFIG_MAP) Map arthasConfigMap, Environment environment, ArthasProperties arthasProperties) { + arthasConfigMap = StringUtils.removeDashKey(arthasConfigMap); ArthasProperties.updateArthasConfigMapDefaultValue(arthasConfigMap); String appName = environment.getProperty(SpringProperties.SPRING_APPLICATION_NAME); @@ -124,87 +112,11 @@ public static ArthasAgent init(Map arthasConfigMap, Environment mapWithPrefix.put(ARTHAS_PROPERTIES_PREFIX + entry.getKey(), entry.getValue()); } - final ArthasAgent arthasAgent = new ArthasAgent(mapWithPrefix, arthasProperties.getHome(), + final ArthasAgent arthasAgent = new CustomArthasAgent(mapWithPrefix, arthasProperties.getHome(), arthasProperties.isSlientInit(), null); arthasAgent.init(); log.info(ARTHAS_AGENT_START_SUCCESS); return arthasAgent; } - - public static void destroy(Map arthasConfigMap, - ArthasProperties arthasProperties) { - String arthasHome = arthasProperties.getHome(); - try { - Instrumentation instrumentation = ByteBuddyAgent.install(); - - if (arthasHome == null || arthasHome.trim().isEmpty()) { - ClassLoader classLoader = ArthasAgent.class.getClassLoader(); - URL coreJarUrl = classLoader.getResource(ARTHAS_BIN_ZIP); - if (coreJarUrl != null) { - File tempArthasDir = findTempDir(); - arthasHome = tempArthasDir.getAbsolutePath(); - } else { - throw new IllegalArgumentException("can not getResources arthas-bin.zip from classloader: " - + classLoader); - } - } - File arthasCoreJarFile = new File(arthasHome, ARTHAS_CORE_JAR); - if (!arthasCoreJarFile.exists()) { - throw new IllegalArgumentException("can not find arthas-core.jar under arthasHome: {}" + arthasHome); - } - AttachArthasClassloader arthasClassLoader = new AttachArthasClassloader( - new URL[] { arthasCoreJarFile.toURI().toURL() }); - Class bootstrapClass = arthasClassLoader.loadClass(ARTHAS_BOOTSTRAP); - - Object bootstrap = bootstrapClass.getMethod(GET_INSTANCE, Instrumentation.class, Map.class) - .invoke(null, instrumentation, arthasConfigMap); - bootstrapClass.getMethod(DESTROY).invoke(bootstrap); - } catch (Throwable e) { - log.error(e.getMessage(), e); - } - } - - private static List listArthasDirs(File baseDir) { - return Stream.of(baseDir.listFiles((dir, name) -> ARTHAS_DIR_PATTERN.matcher(name).matches())) - .collect(Collectors.toList()); - } - - private static Date extractTimestamp(File dir) { - Matcher matcher = ARTHAS_DIR_PATTERN.matcher(dir.getName()); - if (matcher.matches()) { - String timestampStr = matcher.group(1); - SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); - try { - return sdf.parse(timestampStr); - } catch (ParseException e) { - throw new IllegalArgumentException("Invalid timestamp format in directory name: " + dir.getName(), e); - } - } - return null; - } - - private static File findLatestArthasDir(File baseDir) { - List dirs = listArthasDirs(baseDir); - if (!dirs.isEmpty()) { - return dirs.stream() - .max(Comparator.comparing(ArthasAutoConfiguration::extractTimestamp)) - .orElse(null); - } - return null; - } - - public static File findTempDir() { - File baseDir = new File(System.getProperty("java.io.tmpdir")); - String baseName = "arthas-" + System.currentTimeMillis() + "-"; - - // 尝试查找时间戳最大的以 "arthas-" 开头的目录 - File latestDir = findLatestArthasDir(baseDir); - if (latestDir != null) { - return latestDir; - } - - throw new IllegalStateException("Failed to find directory within " + TEMP_DIR_ATTEMPTS - + " attempts (tried " + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')'); - } } diff --git a/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/src/main/java/org/ylzl/eden/arthas/spring/boot/autoconfigure/ArthasEnvironmentChangeListener.java b/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/src/main/java/org/ylzl/eden/arthas/spring/boot/autoconfigure/ArthasEnvironmentChangeListener.java index 97a54c9e..def4fdca 100644 --- a/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/src/main/java/org/ylzl/eden/arthas/spring/boot/autoconfigure/ArthasEnvironmentChangeListener.java +++ b/eden-components/eden-spring-boot-starters/eden-arthas-spring-boot-starter/src/main/java/org/ylzl/eden/arthas/spring/boot/autoconfigure/ArthasEnvironmentChangeListener.java @@ -17,7 +17,6 @@ package org.ylzl.eden.arthas.spring.boot.autoconfigure; import com.alibaba.arthas.spring.ArthasProperties; -import com.taobao.arthas.agent.attach.ArthasAgent; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; @@ -26,11 +25,11 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.core.env.Environment; +import org.ylzl.eden.arthas.spring.boot.attach.CustomArthasAgent; import org.ylzl.eden.arthas.spring.boot.env.SpringArthasProperties; import java.util.Map; import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; /** * Arthas 开关监听器 @@ -42,18 +41,12 @@ @Slf4j public class ArthasEnvironmentChangeListener implements ApplicationListener { - public static final AtomicBoolean REGISTER_STATE = new AtomicBoolean(true); - public static final String ARTHAS_AGENT = "arthasAgent"; public static final String REGISTER_ARTHAS = "Register arthas to {}"; - public static final String ARTHAS_ALREADY_REGISTERED = "Arthas already registered"; - public static final String DESTROY_ARTHAS = "Destroy arthas from {}"; - public static final String ARTHAS_ALREADY_DESTROY = "Arthas already destroy"; - private final ApplicationContext applicationContext; private final Environment environment; @@ -78,14 +71,10 @@ public void onApplicationEvent(EnvironmentChangeEvent event) { } private void registerBean() { - if (!REGISTER_STATE.compareAndSet(false, true)) { - log.info(ARTHAS_ALREADY_REGISTERED); - return; - } log.info(REGISTER_ARTHAS, arthasProperties.getTunnelServer()); DefaultListableBeanFactory defaultListableBeanFactory = getDefaultListableBeanFactory(); if (defaultListableBeanFactory.containsBean(ARTHAS_AGENT)) { - ((ArthasAgent) defaultListableBeanFactory.getBean(ARTHAS_AGENT)).init(); + ((CustomArthasAgent) defaultListableBeanFactory.getBean(ARTHAS_AGENT)).init(); } else { defaultListableBeanFactory.registerSingleton(ARTHAS_AGENT, ArthasAutoConfiguration.init(arthasConfigMap, environment, arthasProperties)); @@ -93,16 +82,12 @@ private void registerBean() { } private void destroyBean() { - if (!REGISTER_STATE.compareAndSet(true, false)) { - log.info(ARTHAS_ALREADY_DESTROY); - return; - } log.info(DESTROY_ARTHAS, arthasProperties.getTunnelServer()); DefaultListableBeanFactory defaultListableBeanFactory = getDefaultListableBeanFactory(); if (defaultListableBeanFactory.containsBean(ARTHAS_AGENT)) { + ((CustomArthasAgent) defaultListableBeanFactory.getBean(ARTHAS_AGENT)).destroy(); defaultListableBeanFactory.destroySingleton(ARTHAS_AGENT); } - ArthasAutoConfiguration.destroy(arthasConfigMap, arthasProperties); } @NotNull diff --git a/eden-components/eden-spring-test/pom.xml b/eden-components/eden-spring-test/pom.xml index 0b5bc697..75c2279e 100644 --- a/eden-components/eden-spring-test/pom.xml +++ b/eden-components/eden-spring-test/pom.xml @@ -207,6 +207,14 @@ log4j log4j + + logback-classic + ch.qos.logback + + + logback-core + ch.qos.logback +