Skip to content

Commit

Permalink
[alibaba#11956] Refactor nacos client logging module, use SPI load cu…
Browse files Browse the repository at this point in the history
…rrent logger adapter. (alibaba#11964)

* Add NacosLoggingAdapter

* Refactor Logback Logging adapter to Nacos logging adapter.

* Refactor log4j2 Logging adapter to Nacos logging adapter.

* Remove useless abstract class

* Add and Adapt log4j2 impl to SPI.

* Remove useless method in NacosLogbackConfigurator

* Fix IT ClassNotFound problem
  • Loading branch information
KomachiSion authored Apr 16, 2024
1 parent 2005ca6 commit 5c19ac1
Show file tree
Hide file tree
Showing 18 changed files with 430 additions and 345 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@

package com.alibaba.nacos.client.logging;

import com.alibaba.nacos.client.logging.log4j2.Log4J2NacosLogging;
import com.alibaba.nacos.client.logging.logback.LogbackNacosLogging;
import org.slf4j.LoggerFactory;
import com.alibaba.nacos.common.executor.ExecutorFactory;
import com.alibaba.nacos.common.executor.NameThreadFactory;
import com.alibaba.nacos.common.spi.NacosServiceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
* nacos logging.
Expand All @@ -30,18 +34,41 @@ public class NacosLogging {

private static final Logger LOGGER = LoggerFactory.getLogger(NacosLogging.class);

private AbstractNacosLogging nacosLogging;
private NacosLoggingAdapter loggingAdapter;

private boolean isLogback = false;
private NacosLoggingProperties loggingProperties;

private NacosLogging() {
try {
Class.forName("ch.qos.logback.classic.Logger");
nacosLogging = new LogbackNacosLogging();
isLogback = true;
} catch (ClassNotFoundException e) {
nacosLogging = new Log4J2NacosLogging();
initLoggingAdapter();
}

private void initLoggingAdapter() {
Class<? extends Logger> loggerClass = LOGGER.getClass();
for (NacosLoggingAdapter each : NacosServiceLoader.load(NacosLoggingAdapter.class)) {
LOGGER.info("Nacos Logging Adapter: {}", each.getClass().getName());
if (each.isEnabled() && each.isAdaptedLogger(loggerClass)) {
LOGGER.info("Nacos Logging Adapter: {} match {} success.", each.getClass().getName(),
loggerClass.getName());
loggingProperties = new NacosLoggingProperties(each.getDefaultConfigLocation());
loggingAdapter = each;
}
}
if (null == loggingAdapter) {
LOGGER.warn("Nacos Logging don't find adapter, logging will print into application logs.");
return;
}
scheduleReloadTask();
}

private void scheduleReloadTask() {
ScheduledExecutorService reloadContextService = ExecutorFactory.Managed
.newSingleScheduledExecutorService("Nacos-Client",
new NameThreadFactory("com.alibaba.nacos.client.logging"));
reloadContextService.scheduleAtFixedRate(() -> {
if (loggingAdapter.isNeedReloadConfiguration()) {
loggingAdapter.loadConfiguration(loggingProperties);
}
}, 0, loggingProperties.getReloadInternal(), TimeUnit.SECONDS);
}

private static class NacosLoggingInstance {
Expand All @@ -58,10 +85,12 @@ public static NacosLogging getInstance() {
*/
public void loadConfiguration() {
try {
nacosLogging.loadConfiguration();
if (null != loggingAdapter) {
loggingAdapter.loadConfiguration(loggingProperties);
}
} catch (Throwable t) {
String loggerName = isLogback ? "Logback" : "Log4j";
LOGGER.warn("Load {} Configuration of Nacos fail, message: {}", loggerName, t.getMessage());
LOGGER.warn("Load {} Configuration of Nacos fail, message: {}", LOGGER.getClass().getName(),
t.getMessage());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* 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
*
* 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.alibaba.nacos.client.logging;

/**
* Nacos client logging adapter.
*
* @author xiweng.yy
*/
public interface NacosLoggingAdapter {

/**
* Whether current adapter is adapted for specified logger class.
*
* @param loggerClass {@link org.slf4j.Logger} implementation class
* @return {@code true} if current adapter can adapt this {@link org.slf4j.Logger} implementation, otherwise {@code
* false}
*/
boolean isAdaptedLogger(Class<?> loggerClass);

/**
* Load Nacos logging configuration into log context.
*
* @param loggingProperties logging properties
*/
void loadConfiguration(NacosLoggingProperties loggingProperties);

/**
* Whether need reload configuration into log context.
*
* @return {@code true} when context don't contain nacos logging configuration. otherwise {@code false}
*/
boolean isNeedReloadConfiguration();

/**
* Get current logging default config location.
*
* @return default config location
*/
String getDefaultConfigLocation();

/**
* Whether current adapter enabled, design for users which want to log nacos client into app logs.
*
* @return {@code true} when enabled, otherwise {@code false}, default {@code true}
*/
default boolean isEnabled() {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* 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
*
* 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.alibaba.nacos.client.logging;

import com.alibaba.nacos.client.env.NacosClientProperties;
import com.alibaba.nacos.common.utils.ConvertUtils;
import com.alibaba.nacos.common.utils.StringUtils;

/**
* Nacos Logging Properties, save some nacos logging properties.
*
* @author xiweng.yy
*/
public class NacosLoggingProperties {

private static final String NACOS_LOGGING_CONFIG_PROPERTY = "nacos.logging.config";

private static final String NACOS_LOGGING_DEFAULT_CONFIG_ENABLED_PROPERTY = "nacos.logging.default.config.enabled";

private static final String NACOS_LOGGING_RELOAD_INTERVAL_PROPERTY = "nacos.logging.reload.interval.seconds";

private static final long DEFAULT_NACOS_LOGGING_RELOAD_INTERVAL = 10L;

private final String defaultLocation;

public NacosLoggingProperties(String defaultLocation) {
this.defaultLocation = defaultLocation;
}

/**
* Get the location of nacos logging configuration.
*
* @return location of nacos logging configuration
*/
public String getLocation() {
String location = NacosClientProperties.PROTOTYPE.getProperty(NACOS_LOGGING_CONFIG_PROPERTY);
if (StringUtils.isBlank(location)) {
if (isDefaultLocationEnabled()) {
return defaultLocation;
}
return null;
}
return location;
}

/**
* Is default location enabled.
*
* <p> It is judged when user don't set the location of nacos logging configuration. </p>
*
* @return {@code true} if default location enabled, otherwise {@code false}, default is {@code true}
*/
private boolean isDefaultLocationEnabled() {
String property = NacosClientProperties.PROTOTYPE.getProperty(NACOS_LOGGING_DEFAULT_CONFIG_ENABLED_PROPERTY);
return property == null || ConvertUtils.toBoolean(property);
}

/**
* Get reload internal.
*
* @return reload internal
*/
public long getReloadInternal() {
String interval = NacosClientProperties.PROTOTYPE.getProperty(NACOS_LOGGING_RELOAD_INTERVAL_PROPERTY);
return ConvertUtils.toLong(interval, DEFAULT_NACOS_LOGGING_RELOAD_INTERVAL);
}

/**
* get property value.
*
* @param source source
* @param defaultValue defaultValue
* @return value
*/
public String getValue(String source, String defaultValue) {
return NacosClientProperties.PROTOTYPE.getProperty(source, defaultValue);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

package com.alibaba.nacos.client.logging.log4j2;

import com.alibaba.nacos.client.logging.AbstractNacosLogging;
import com.alibaba.nacos.client.logging.NacosLoggingAdapter;
import com.alibaba.nacos.client.logging.NacosLoggingProperties;
import com.alibaba.nacos.common.utils.ResourceUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import org.apache.logging.log4j.LogManager;
Expand All @@ -36,9 +37,10 @@
* Support for Log4j version 2.7 or higher
*
* @author <a href="mailto:[email protected]">hxy1991</a>
* @author xiweng.yy
* @since 0.9.0
*/
public class Log4J2NacosLogging extends AbstractNacosLogging {
public class Log4J2NacosLoggingAdapter implements NacosLoggingAdapter {

private static final String NACOS_LOG4J2_LOCATION = "classpath:nacos-log4j2.xml";

Expand All @@ -48,14 +50,51 @@ public class Log4J2NacosLogging extends AbstractNacosLogging {

private static final String NACOS_LOG4J2_PLUGIN_PACKAGE = "com.alibaba.nacos.client.logging.log4j2";

private final String location = getLocation(NACOS_LOG4J2_LOCATION);
private static final String APPENDER_MARK = "ASYNC_NAMING";

private static final String LOG4J2_CLASSES = "org.apache.logging.slf4j.Log4jLogger";

@Override
public void loadConfiguration() {
public boolean isAdaptedLogger(Class<?> loggerClass) {
Class<?> expectedLoggerClass = getExpectedLoggerClass();
return null != expectedLoggerClass && expectedLoggerClass.isAssignableFrom(loggerClass);
}

private Class<?> getExpectedLoggerClass() {
try {
return Class.forName(LOG4J2_CLASSES);
} catch (ClassNotFoundException e) {
return null;
}
}

@Override
public boolean isNeedReloadConfiguration() {
final LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
final Configuration contextConfiguration = loggerContext.getConfiguration();
for (Map.Entry<String, Appender> entry : contextConfiguration.getAppenders().entrySet()) {
if (APPENDER_MARK.equals(entry.getValue().getName())) {
return false;
}
}
return true;
}

@Override
public String getDefaultConfigLocation() {
return NACOS_LOG4J2_LOCATION;
}

@Override
public void loadConfiguration(NacosLoggingProperties loggingProperties) {
String location = loggingProperties.getLocation();
loadConfiguration(location);
}

private void loadConfiguration(String location) {
if (StringUtils.isBlank(location)) {
return;
}

final LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
final Configuration contextConfiguration = loggerContext.getConfiguration();

Expand Down
Loading

0 comments on commit 5c19ac1

Please sign in to comment.