【log4j2日志框架】修改转储日志文件权限

0.背景

对于安全要求严格的系统,转储的压缩日志文件,要求文件权限为只读,而找遍了log4j2的资料,都没发现有这样配置,log4j2框架对于日志的默认权限都是640,无论如何也为日志文件保留可写权限,貌似无法单独为压缩后的日志配置权限。不过log4j2是支持自定义日志滚动策略的,干脆直接从源代码研究如何扩展log4j2的日志插件。

1.分析解决思路

一般情况我们选择rolling.strategy.type的时候选择的都是DefaultRolloverStrategy,整个滚动策略的实现还是挺复杂的,我只想以最小的改动实现这个功能。DefaultRolloverStrategy核心逻辑在rollover中,该方法是在构造一个RolloverDescription的实例,观察构造RolloverDescription实例需要的参数

在这里插入图片描述
在这里插入图片描述
最后一个参数正是压缩文件的处理类,前三个参数不用管。当我们配置的压缩日志格式为gz时,第四个参数的实现类是GzCompressAction,其核心方法execute就是在将.log文件压缩为.gz文件。整个日志的滚动策略我都不想修改,只想在GzCompressAction的execute方法之后插入一段修改压缩文件权限的方法。

2、扩展GzCompressAction

在这里插入图片描述
GzCompressAction由final修饰无法继承,最简单的办法就是继承它的父类,并将GzCompressAction作为成员。实现execute方法时不用关系原GzCompressAction具体的逻辑,直接调用成员的execute方法,然后调用我提供的修改文件权限的方法。这样便实现我刚说的不改动原有逻辑,只在压缩后修改文件权限。

public class CustomGzCompressAction extends AbstractAction {
    private final GzCompressAction gzCompressAction;

    public CustomGzCompressAction(GzCompressAction gzCompressAction) {
        this.gzCompressAction = gzCompressAction;
    }

    @Override
    public boolean execute() throws IOException {
        boolean result = gzCompressAction.execute();
        File destination = gzCompressAction.getDestination();
        if (destination != null) {
            FilePermissionUtil.chmodLogFile(destination);
        }
        return result;
    }
}

FilePermissionUtil

public class FilePermissionUtil {
    private static final Logger LOG = LoggerFactory.getLogger(FilePermissionUtil.class);

    /**
     * 修改文件权限为只读
     *
     * @param fileName 文件路径
     */
    public static void chmodLogFile(File fileName) {
        try {
            LOG.info("change log file permission");
            Set<PosixFilePermission> perms = EnumSet.of(OWNER_READ, GROUP_READ);
            if (Files.readAttributes(fileName.toPath(), PosixFileAttributes.class) != null) {
                PosixFileAttributes attr = Files.readAttributes(fileName.toPath(), PosixFileAttributes.class);
                attr.permissions().clear();
            }
            Files.setPosixFilePermissions(fileName.toPath(), perms);
        } catch (FileNotFoundException e) {
            LOG.error("file nod found ,fileName={}", fileName);
        } catch (IOException e) {
            LOG.error("change file permission error", e);
        }
    }
}

3、扩展DefaultRolloverStrategy

由于log4j2是以插件的形式加载滚动策略的,因此我们要像DefaultRolloverStrategy一样将自定义的滚动策略定义为一个插件。这里直接将DefaultRolloverStrategy的代码拷贝过来,利用DefaultRolloverStrategy的实例构造CustomRolloverStrategy。

@Plugin(name = "CustomRolloverStrategy", category = Core.CATEGORY_NAME, printObject = true)
public class CustomRolloverStrategy extends DefaultRolloverStrategy {
    private static final Logger LOG = LoggerFactory.getLogger(CustomRolloverStrategy.class);

    protected CustomRolloverStrategy(int minIndex, int maxIndex,
                                    boolean useMax, int compressionLevel,
                                    StrSubstitutor strSubstitutor, Action[] customActions,
                                    boolean stopCustomActionsOnError,
                                    String tempCompressedFilePatternString) {
        super(minIndex, maxIndex, useMax,
                compressionLevel, strSubstitutor,
                customActions, stopCustomActionsOnError,
                tempCompressedFilePatternString);
    }

    protected CustomRolloverStrategy(
            int minIndex, int maxIndex, boolean useMax,
            int compressionLevel, StrSubstitutor strSubstitutor,
            Action[] customActions, boolean stopCustomActionsOnError) {
        super(minIndex, maxIndex, useMax,
                compressionLevel, strSubstitutor,
                customActions, stopCustomActionsOnError);
    }

    /**
     * Strateg的构造factory
     *
     * @param max                      最大文件个数
     * @param min                      最小文件个数
     * @param fileIndex                最大文件索引
     * @param compressionLevelStr      压缩等级
     * @param customActions            自定义Action
     * @param stopCustomActionsOnError 自定义Action发生错误时是否停止
     * @param config                   其他配置
     * @return CustomRolloverStrategy
     */
    @PluginFactory
    public static CustomRolloverStrategy createStrategy(
            // @formatter:off
            @PluginAttribute("max") final String max,
            @PluginAttribute("min") final String min,
            @PluginAttribute("fileIndex") final String fileIndex,
            @PluginAttribute("compressionLevel") final String compressionLevelStr,
            @PluginElement("Actions") final Action[] customActions,
            @PluginAttribute(value = "stopCustomActionsOnError",
                    defaultBoolean = true)
            final boolean stopCustomActionsOnError,
            @PluginConfiguration final Configuration config) {
        DefaultRolloverStrategy defaultRolloverStrategy = DefaultRolloverStrategy.newBuilder()
                .withMin(min)
                .withMax(max)
                .withFileIndex(fileIndex)
                .withCompressionLevelStr(compressionLevelStr)
                .withCustomActions(customActions)
                .withStopCustomActionsOnError(stopCustomActionsOnError)
                .withConfig(config)
                .build();
        CustomRolloverStrategy customRolloverStrategy
                = new CustomRolloverStrategy(defaultRolloverStrategy.getMinIndex(),
                defaultRolloverStrategy.getMaxIndex(), defaultRolloverStrategy.isUseMax(),
                defaultRolloverStrategy.getCompressionLevel(),
                defaultRolloverStrategy.getStrSubstitutor(),
                customActions, defaultRolloverStrategy.isStopCustomActionsOnError());
        return customRolloverStrategy;
    }

    /**
     * 重写的DefaultRolloverStrategy的rollover
     *
     * @param manager manager
     * @return RolloverDescription
     * @throws SecurityException
     */
    @Override
    public RolloverDescription rollover(RollingFileManager manager) throws SecurityException {
        RolloverDescription result = super.rollover(manager);
        Action asynchronous = result.getAsynchronous();
        if (asynchronous instanceof GzCompressAction) {
            asynchronous = new CustomGzCompressAction((GzCompressAction) asynchronous);
        }

        return new RolloverDescriptionImpl(result.getActiveFileName(), false, result.getSynchronous(), asynchronous);
    }

}

rollover的实现也是调用父类的rollover,然后将父类返回对象中的asynchronous替换为我们扩展的CustomGzCompressAction,其他参数不变。

4、配置

将log4j2.properties中的rolling.strategy.type全部替换为CustomRolloverStrategy,便实现我们要的修改压缩日志文件权限的功能。
在这里插入图片描述

5、效果

记录中的日志权限为6xx,压缩后的gz为440
在这里插入图片描述

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值