日志文件转储压缩实现

简介:

日志的转储和压缩是非常关键的,它不仅可以减少硬盘空间占用,主要还可以在发生故障时根据日志定位出故障原因。下面来看看golang和java的文件转储实现。

go语言:

用到了filepath包下的Walk方法,具体说明可以参看历史文章:

go语言path/filepath包之Walk源码解析

 

package main

import (
 "fmt"
 "os"
 "io"
 "archive/zip"
 "path/filepath"
 "time"
 "log"
)

func main() {

 logFile := "D:/tmp/successLog/logs/root.log"

 backFile := "D:/tmp/successLog/logs/root_" + time.Now().Format("20060102150405") + ".zip"
 
 err := zipFile(logFile, backFile)
 if err != nil {
   log.Println(fmt.Sprintf("zip file %s to %s error : %v", logFile, backFile, err))
   return
 } else {
   os.Remove(logFile)
 }

 //转储后创建新文件
 //createFile()

 //修改文件权限
 //os.Chmod(backfile, 0400)

 //删除备份文件
 //deleteOldBackfiles(dir)
}


func zipFile(source, target string) error {

 zipFile, err := os.OpenFile(target, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0440)
 if err != nil {
   log.Println(err)
   return err
 }
 defer zipFile.Close()

 archive := zip.NewWriter(zipFile)
 defer archive.Close()

 return filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
   if err != nil {
     return err
   }

   header, err := zip.FileInfoHeader(info)
   if err != nil {
     return err
   }

   if !info.IsDir() {
     header.Method = zip.Deflate
   }
   header.SetModTime(time.Now().UTC())
   header.Name = path
   writer, err := archive.CreateHeader(header)
   if err != nil {
     return err
   }

   if info.IsDir() {
     return nil
   }
   file, err := os.Open(path)

   if err != nil {
     return err
   }
   defer file.Close()

   _, err = io.Copy(writer, file)
   return err
 })
}

ed55914392720fd78113833a6ab05ca213e4f251

java版:


说明见注释。

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;



import java.io.*;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

import java.util.zip.CRC32;

import java.util.zip.CheckedOutputStream;

import java.util.zip.ZipEntry;

import java.util.zip.ZipOutputStream;



/**

* @program: website

* @description: 转储压缩文件

* @author: smallsoup

* @create: 2018-08-12 17:58

**/



public class ZipFile {



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



/**

* 格式化文件名格式

*/

private static final String AUDIT_LOG_FORMAT = "yyyyMMddHHmmssSSS";



/**

* 压缩后文件后缀

*/

private static final String AUDIT_FILE_ZIP_SUFFIX = ".zip";



/**

* 压缩前文件后缀

*/

private static final String AUDIT_FILE_EXT = ".log";



private static final int ZIP_BUFFER = 4096;



/**

* 控制压缩后的文件解压后是否带base路径

*/

private static final String rootPath = "";





public static void main(String[] args) throws IOException {



System.out.println();



new ZipFile().zipAuditLogFile("D:/tmp/successLog/logs/root.log");

}



/**

* 日志压缩

*

* @param waitZipFile 要压缩文件名

* @throws IOException

*/

private void zipAuditLogFile(String waitZipFile) throws IOException {

File oldFile = new File(waitZipFile);



if (!oldFile.exists()) {

LOGGER.error("zipAuditLogFile name is {} not exist", waitZipFile);

return;

}



//生成zip文件名

DateFormat dataFormat = new SimpleDateFormat(AUDIT_LOG_FORMAT);

String formatTime = dataFormat.format(oldFile.lastModified());



int end = waitZipFile.length() - AUDIT_FILE_EXT.length();

String zipFileName = waitZipFile.subSequence(0, end) + "_" + formatTime + AUDIT_FILE_ZIP_SUFFIX;



File zipFile = new File(zipFileName);



FileOutputStream zipfos = null;

ZipOutputStream zipOs = null;

CheckedOutputStream cos = null;





try {

zipfos = new FileOutputStream(zipFile);

cos = new CheckedOutputStream(zipfos, new CRC32());



zipOs = new ZipOutputStream(cos);



compress(oldFile, zipOs, rootPath);



if (zipFile.exists()) {

// 写完的日志文件权限改为400

try {

//linux上才可以运行,windows上需要装cygwin并且把cygwin的bin目录加到环境变量的path中才可以

Runtime.getRuntime().exec("chmod 400 -R " + zipFile);

//压缩后删除旧文件

boolean isDelete = oldFile.delete();

//创建新文件

if (isDelete) {

oldFile.createNewFile();

}

// boolean isSuccess = PathUtil.setFilePermision(zipFile.toPath(), ARCHIVE_LOGFILE_PERMISION);

// LOGGER.warn("set archive file: {}, permision result is {}", zipFile.getAbsolutePath(), isSuccess);

} catch (IOException e) {

LOGGER.error("set archive file:{} permision catch an error: {}", zipFile, e);

}

}



} finally {



if (null != zipOs) {

zipOs.close();

}



if (null != cos) {

cos.close();

}



if (null != zipfos) {

zipfos.close();

}

}

}



/**

* 压缩文件或目录

*

* @param oldFile 要压缩的文件

* @param zipOut 压缩文件流

* @param baseDir baseDir

* @throws IOException

*/

private void compress(File oldFile, ZipOutputStream zipOut, String baseDir) throws IOException {



if (oldFile.isDirectory()) {



compressDirectory(oldFile, zipOut, baseDir);



} else {

compressFile(oldFile, zipOut, baseDir);

}

}



/**

* 压缩目录

*

* @param dir 要压缩的目录

* @param zipOut 压缩文件流

* @param baseDir baseDir

* @throws IOException

*/

private void compressDirectory(File dir, ZipOutputStream zipOut, String baseDir) throws IOException {



File[] files = dir.listFiles();



for (File file : files) {

compress(file, zipOut, baseDir + dir.getName() + File.separator);

}

}



/**

* 压缩文件

*

* @param oldFile 要压缩的文件

* @param zipOut 压缩文件流

* @param baseDir baseDir

* @throws IOException

*/

private void compressFile(File oldFile, ZipOutputStream zipOut, String baseDir) throws IOException {



if (!oldFile.exists()) {

LOGGER.error("zipAuditLogFile name is {} not exist", oldFile);

return;

}



BufferedInputStream bis = null;



try {



bis = new BufferedInputStream(new FileInputStream(oldFile));



ZipEntry zipEntry = new ZipEntry(baseDir + oldFile.getName());



zipOut.putNextEntry(zipEntry);



int count;



byte data[] = new byte[ZIP_BUFFER];



while ((count = bis.read(data, 0, ZIP_BUFFER)) != -1) {

zipOut.write(data, 0, count);

}



} finally {

if (null != bis) {

bis.close();

}

}



}



}


3a0faf6e66c043028b7c90693b877f85d83df0c1

修改权限也可以利用Java7中NIO.2对元数据文件操作的支持,具体可以查看NIO包的使用,其相关教程见文末说明。

代码如下:

package com.website.common;



import java.io.IOException;

import java.nio.file.FileSystems;

import java.nio.file.Files;

import java.nio.file.Path;

import java.nio.file.attribute.PosixFilePermission;

import java.nio.file.attribute.PosixFilePermissions;

import java.util.Set;



/**

* 提供文件路径公共函数 改变权限,判断是否正规文件,判断是否路径在安全路径下等

*

* @program: website

* @description: 路径工具, 修改权限

* @author: smallsoup

* @create: 2018-08-14 07:56

**/



public class PathUtil {



/**

* POSIX表示可移植操作系统接口,并不局限于unix类系统

*/

private static final boolean ISPOSIX = FileSystems.getDefault().supportedFileAttributeViews().contains("posix");



/**

* 数字权限格式,如600

*/

private static final int PERM_LEN_THREE = 3;



/**

* 如765 rwxrw_r_x

*/

private static final int PERM_LEN_NINE = 9;





/**

* 设置文件的权限,尽在posix下有效

*

* @param file 文件

* @param perm 权限 类似 “rw-r-----”, "640"

* @return true 修改成功 false 修改失败

* @throws IOException

*/

public static boolean setFilePermision(Path file, String perm) throws IOException {

if (!ISPOSIX) {

return true;

}

// 750 -> "rwxr-x---"

if (perm.length() == PERM_LEN_THREE) {

perm = trans2StrPerm(perm);

}



if (perm.length() != PERM_LEN_NINE) {

return false;

}



Set<PosixFilePermission> perms = PosixFilePermissions.fromString(perm);

Files.setPosixFilePermissions(file, perms);

return true;

}



/**

* 转换

*

* @param digitPerm 长度为3的数字字符串

* @return

*/

private static String trans2StrPerm(String digitPerm) {

StringBuilder builder = new StringBuilder(9);

// owner

builder.append(toStringPerm(digitPerm.charAt(0)));

// group

builder.append(toStringPerm(digitPerm.charAt(1)));

// other

builder.append(toStringPerm(digitPerm.charAt(2)));

return builder.toString();

}



private static String toStringPerm(char ch) {

switch (ch - '0') {

case 7:

return "rwx";

case 6:

return "rw-";

case 5:

return "r-x";

case 4:

return "r--";

case 3:

return "-wx";

case 2:

return "-w-";

case 1:

return "--x";

case 0:

return "---";

default:

return "";

}

}

}


原文发布时间为:2018-08-15
本文作者:小碗汤
本文来自云栖社区合作伙伴“ 我的小碗汤”,了解相关信息可以关注“ 我的小碗汤”。
相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
2月前
|
存储 监控 算法
防止员工泄密软件中文件访问日志管理的 Go 语言 B + 树算法
B+树凭借高效范围查询与稳定插入删除性能,为防止员工泄密软件提供高响应、可追溯的日志管理方案,显著提升海量文件操作日志的存储与检索效率。
116 2
|
Java Apache 开发工具
【Azure 事件中心】 org.slf4j.Logger 收集 Event Hub SDK(Java) 输出日志并以文件形式保存
【Azure 事件中心】 org.slf4j.Logger 收集 Event Hub SDK(Java) 输出日志并以文件形式保存
226 1
|
10月前
|
运维 应用服务中间件 nginx
docker运维查看指定应用log文件位置和名称
通过本文的方法,您可以更高效地管理和查看Docker容器中的日志文件,确保应用运行状态可控和可监测。
1412 28
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
382 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
SQL Oracle 关系型数据库
【赵渝强老师】Oracle的控制文件与归档日志文件
本文介绍了Oracle数据库中的控制文件和归档日志文件。控制文件记录了数据库的物理结构信息,如数据库名、数据文件和联机日志文件的位置等。为了保护数据库,通常会进行控制文件的多路复用。归档日志文件是联机重做日志文件的副本,用于记录数据库的变更历史。文章还提供了相关SQL语句,帮助查看和设置数据库的日志模式。
297 1
【赵渝强老师】Oracle的控制文件与归档日志文件
|
存储 SQL 关系型数据库
【赵渝强老师】PostgreSQL的运行日志文件
PostgreSQL的物理存储结构包括数据文件、日志文件等。运行日志默认未开启,需配置`postgresql.conf`文件中的相关参数如`log_destination`、`log_directory`等,以记录数据库状态、错误信息等。示例配置中启用了CSV格式日志,便于管理和分析。通过创建表操作,可查看生成的日志文件,了解具体日志内容。
365 3
|
监控 Linux 应用服务中间件
系统监控:使用日志文件 journalctl的使用
本文介绍了如何使用`journalctl`命令来监控和查看Linux系统的日志文件,包括查看特定行数、过滤日志级别、实时跟踪日志、按时间段查询日志以及日志轮换和压缩的配置。
764 2
系统监控:使用日志文件 journalctl的使用
|
SQL 关系型数据库 MySQL
【赵渝强老师】MySQL的全量日志文件
MySQL全量日志记录所有操作的SQL语句,默认禁用。启用后,可通过`show variables like %general_log%检查状态,使用`set global general_log=ON`临时开启,执行查询并查看日志文件以追踪SQL执行详情。
215 4
|
Oracle 关系型数据库 数据库
【赵渝强老师】Oracle的参数文件与告警日志文件
本文介绍了Oracle数据库的参数文件和告警日志文件。参数文件分为初始化参数文件(PFile)和服务器端参数文件(SPFile),在数据库启动时读取并分配资源。告警日志文件记录了数据库的重要活动、错误和警告信息,帮助诊断问题。文中还提供了相关视频讲解和示例代码。
279 1
|
SQL 数据库
为什么 SQL 日志文件很大,我应该如何处理?
为什么 SQL 日志文件很大,我应该如何处理?