Skip to content
This repository has been archived by the owner on Feb 18, 2024. It is now read-only.

Commit

Permalink
add sofa-serverless-adapter-logback
Browse files Browse the repository at this point in the history
  • Loading branch information
知行 committed Nov 16, 2023
1 parent 52aff88 commit de4f364
Show file tree
Hide file tree
Showing 15 changed files with 595 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
<packaging>pom</packaging>
<modules>
<module>sofa-serverless-adapter-log4j2</module>
<module>sofa-serverless-adapter-logback</module>
</modules>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alipay.sofa.serverless</groupId>
<artifactId>sofa-serverless-adapter-ext</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>sofa-serverless-adapter-logback</artifactId>
<version>${revision}</version>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<scope>provided</scope>
<version>${spring.boot.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>1.16.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>juint</groupId>
<artifactId>junit-dep</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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 com.alipay.sofa.serverless.logback;

import ch.qos.logback.classic.LoggerContext;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* 按上下文生成 logback context.
*
* @author : chenlei3641
*/
public class SOFAServerlessLogbackLogManagerAdapter {
private static final ThreadLocal<LoggerContext> THREAD_CONTEXT = new ThreadLocal();

public static LoggerContext getContext(ClassLoader cls) {
LoggerContext loggerContext = THREAD_CONTEXT.get();
if (loggerContext == null) {
synchronized (SOFAServerlessLogbackLogManagerAdapter.class) {
if (THREAD_CONTEXT.get() == null) {
loggerContext = new LoggerContext();
THREAD_CONTEXT.set(loggerContext);
} else {
loggerContext = THREAD_CONTEXT.get();
}
}
}
return loggerContext;
}

public static void clearContext(ClassLoader cls) {
THREAD_CONTEXT.remove();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* 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 com.alipay.sofa.serverless.logback;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.spi.FilterReply;
import org.slf4j.Logger;
import org.slf4j.Marker;
import org.springframework.boot.logging.LogFile;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.logging.logback.LogbackLoggingSystem;
import org.springframework.util.StringUtils;
import org.springframework.util.SystemPropertyUtils;

/**
* 支持将配置转换为 logback context.
*
* @author : chenlei3641
*/
public class SOFAServerlessLogbackLoggingSystem extends LogbackLoggingSystem {
private static final String CONFIGURATION_FILE_PROPERTY = "logback.configurationFile";

private static final TurboFilter FILTER = new TurboFilter() {

@Override
public FilterReply decide(Marker marker,
ch.qos.logback.classic.Logger logger,
Level level,
String format,
Object[] params,
Throwable t) {
return FilterReply.DENY;
}

};

public SOFAServerlessLogbackLoggingSystem(ClassLoader classLoader) {
super(classLoader);
}

@Override
public void initialize(LoggingInitializationContext initializationContext,
String configLocation, LogFile logFile) {
LoggerContext loggerContext = getLoggerContext();
if (isAlreadyInitialized(loggerContext)) {
return;
}
//--
if (StringUtils.hasLength(configLocation)) {
initializeWithSpecificConfig(initializationContext, configLocation, logFile);
return;
}
initializeWithConventions(initializationContext, logFile);
//--
loggerContext.getTurboFilterList().remove(FILTER);
markAsInitialized(loggerContext);
if (StringUtils.hasText(System.getProperty(CONFIGURATION_FILE_PROPERTY))) {
getLogger(SOFAServerlessLogbackLoggingSystem.class.getName()).warn(
"Ignoring '" + CONFIGURATION_FILE_PROPERTY
+ "' system property. Please use 'logging.config' instead.");
}
}

private void initializeWithSpecificConfig(LoggingInitializationContext initializationContext,
String configLocation, LogFile logFile) {
configLocation = SystemPropertyUtils.resolvePlaceholders(configLocation);
loadConfiguration(initializationContext, configLocation, logFile);
}

private void initializeWithConventions(LoggingInitializationContext initializationContext,
LogFile logFile) {
String config = getSelfInitializationConfig();
if (config != null && logFile == null) {
// self initialization has occurred, reinitialize in case of property changes
reinitialize(initializationContext);
return;
}
if (config == null) {
config = getSpringInitializationConfig();
}
if (config != null) {
loadConfiguration(initializationContext, config, logFile);
return;
}
loadDefaults(initializationContext, logFile);
}

private LoggerContext getLoggerContext() {
return SOFAServerlessLogbackLogManagerAdapter.getContext(Thread.currentThread()
.getContextClassLoader());
}

private boolean isAlreadyInitialized(LoggerContext loggerContext) {
return loggerContext.getObject(LoggingSystem.class.getName()) != null;
}

private void markAsInitialized(LoggerContext loggerContext) {
loggerContext.putObject(LoggingSystem.class.getName(), new Object());
}

private ch.qos.logback.classic.Logger getLogger(String name) {
LoggerContext factory = getLoggerContext();
return factory.getLogger(getLoggerName(name));
}

private String getLoggerName(String name) {
if (!StringUtils.hasLength(name) || Logger.ROOT_LOGGER_NAME.equals(name)) {
return ROOT_LOGGER_NAME;
}
return name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* 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 com.alipay.sofa.serverless.logback;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;

/**
* 设置日志系统.
*
* @author : chenlei3641
*/
public class SOFAServerlessLogbackSpringContextListener implements GenericApplicationListener,
Ordered {

private static Class<?>[] EVENT_TYPES = { ApplicationStartingEvent.class,
ApplicationEnvironmentPreparedEvent.class, ContextClosedEvent.class };

private static Class<?>[] SOURCE_TYPES = { SpringApplication.class, ApplicationContext.class };

@Override
public boolean supportsEventType(ResolvableType eventType) {
return isAssignableFrom(eventType.getRawClass(), EVENT_TYPES);
}

@Override
public boolean supportsSourceType(Class<?> sourceType) {
return isAssignableFrom(sourceType, SOURCE_TYPES);
}

@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartingEvent) {
onApplicationStartingEvent();
} else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
} else if (event instanceof ContextClosedEvent) {
onContextClosedEvent((ContextClosedEvent) event);
}
}

private void onContextClosedEvent(ContextClosedEvent event) {
SOFAServerlessLogbackLogManagerAdapter.clearContext(Thread.currentThread()
.getContextClassLoader());
}

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
}

private void onApplicationStartingEvent() {
System.setProperty(LoggingSystem.class.getName(),
SOFAServerlessLogbackLoggingSystem.class.getName());
}

@Override
public int getOrder() {
return HIGHEST_PRECEDENCE + 19;
}

private boolean isAssignableFrom(Class<?> type, Class<?>... supportedTypes) {
if (type != null) {
for (Class<?> supportedType : supportedTypes) {
if (supportedType.isAssignableFrom(type)) {
return true;
}
}
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.springframework.context.ApplicationListener=\
com.alipay.sofa.serverless.logback.SOFAServerlessLogbackSpringContextListener
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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 com.alipay.sofa.serverless.logback;

import com.alipay.sofa.serverless.logback.bootstrap.SOFABootApplication;
import com.alipay.sofa.serverless.logback.helper.Log1Print;
import com.alipay.sofa.serverless.logback.helper.Log2Print;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.SystemOutRule;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
* @author : chenlei3641
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SOFABootApplication.class)
public class LogbackDefaultConfigTest {

@Rule
public SystemOutRule systemOutRule = new SystemOutRule().enableLog();

@Test
public void testDefaultConfig() {
new Log1Print().printLog();
new Log2Print().printLog();

String systemLog = systemOutRule.getLog();
Assert.assertTrue(systemLog.contains("log1"));
Assert.assertTrue(systemLog.contains("log2"));
}
}
Loading

0 comments on commit de4f364

Please sign in to comment.