We received a request from a user to analyze and audit the usage status of Web applications. Originally I used logback for log output, so I decided to support it by outputting a CSV file from logback.
--Outputs a UTF-8 CSV file with BOM. --In Excel, when you open a UTF-8 CSV file without BOM, the characters are garbled. --Add a fixed wording header at the beginning of the file to make it easier to read from Excel. --Log files are rotated on a monthly basis.
I made it by referring to Add an expression at the start of every log file using Logback --Stack Overflow.
Prepare an Appender that puts the BOM and fixed wording at the beginning of the file.
AuthFileAppender.java
public class AuthFileAppender extends RollingFileAppender {
@Override
public void openFile(String fileName) throws IOException {
super.openFile(fileName);
File activeFile = new File(getFile());
if (activeFile.exists() && activeFile.isFile() && activeFile.length() == 0) {
//Output BOM and header only when the output target is an empty file
lock.lock();
try {
OutputStream outputStream = super.getOutputStream();
//Output BOM
outputStream.write(0xef);
outputStream.write(0xbb);
outputStream.write(0xbf);
//Output fixed wording (CSV header)
outputStream.write("Operation date,Operation time,User ID,User name,Operation details,Operation target person ID ・ ・ ・\n".getBytes());
if (super.isImmediateFlush()) {
outputStream.flush();
}
} finally {
lock.unlock();
}
}
}
}
--Since I wanted to use the RollingFileAppender mechanism in Logback as it is for monthly log rotation, I will use a class that inherits RollingFileAppender. --For the output target (activeFile), the BOM and fixed wording (CSV header) are output only when the target file is empty. --In the Stack Overflow page above, the fixed wording was set externally, but in this implementation it is hard coded. --In the actual code, application-specific item names are set in the operation details, operation target person ID, and so on.
I wanted to standardize the login user information acquisition process, and I also wanted to standardize Logger, so I decided to prepare a class.
AuthLogger.java
@Component
public class AuthLogger {
/**Logger that outputs audit logs*/
public static final Logger AUTH_LOGGER = LoggerFactory.getLogger(AuthLogger.class);
/**Service dealing with individuals*/
@Autowired
protected PersonService personService;
/**
*The audit log is output without specifying the target individual.
*
* @param operation Operation details
*/
public void log(String operation) {
log(operation, null);
}
/**
*Specify the target individual and output the audit log.
*
* @param operation Operation details
* @param personId ID of the person who handled it
*/
public void log(String operation, String personId) {
SsoLoginData ssoLoginData = SsoLoginDataUtil.getSsoLoginData(); //Get login user information
AUTH_LOGGER.trace(String.join(
",", //Output separated by commas
//Operation date and operation time are logback.Not required here as it is set in the layout in xml
ssoLoginData.getPersonId(), //User ID
ssoLoginData.getUserName(), //User name
operation, //Operation details
personId //User name
//Actually, set the output contents using personService here
));
}
}
--Since it was an application built with SpringBoot, I decided to handle this class as a bean as well. That's why we've added Component
.
--PersonService is DI with @Autowired
.
--When generating Logger, I decided to pass AuthLogger.class as it is.
--Therefore, in logback.xml, the fully qualified class name of AuthLogger is specified as name.
--We have prepared both a method that specifies only the operation content and a method that specifies the ID of the target person who handled it.
--In the process where the target person is not specified, the log is output by the former.
--I'm using String.join
to get the CSV.
--If you want to enclose it in double quotes, or if the output value contains line breaks, we recommend using a CSV-specific library such as opencsv.
Add the following settings to logback.xml.
logback.xml
<appender name="AUTH_APPENDER" class="your.project.web.common.util.AuthFileAppender">
<file>/your/file/path.csv</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/your/file/path.%d{yyyy-MM}.csv</fileNamePattern>
</rollingPolicy>
<encoder>
<charset>UTF-8</charset>
<pattern>%d{yyyy-MM-dd},%d{HH:mm:ss},%msg%n</pattern>
</encoder>
</appender>
<logger name="your.project.web.common.util.AuthLogger" level="TRACE" additivity="false">
<appender-ref ref="AUTH_APPENDER" />
</logger>
--About appender settings
--Use the AuthFileAppender mentioned above.
--The part of / your / file / path
is actually$ {log.auth.output}
, and it is replaced with the value according to the environment running when the application is built.
--The fileNamePattern of the rollingPolicy is % d {yyyy-MM}
to rotate on a monthly basis.
--I decided to use the Logback function to output the operation date and operation time, which are the first two items of CSV. Therefore, % d {yyyy-MM-dd},% d {HH: mm: ss},
is set at the beginning of the pattern.
--About logger settings
--name is the fully qualified class name of AuthLogger as described above.
--If you specified a unique name in AuthLogger when generating Logger, you can specify that name here as well.
--By specifying ʻadditivity = "false" `. Only AUTH_APPENDER is used.
This time, I decided to DI the above-mentioned AuthLogger in the Controller of Spring MVC and execute the log method directly. (Implementation is omitted here.) Depending on the scale and requirements of the project, I think there is an option to output by AOP.
Logback didn't have a function to put a fixed wording (including BOM) at the beginning of the file, so I decided to prepare my own Appender, but it was relatively easy to realize. This time, it was assumed that the user would check the output log file directly in Excel, so we took the above measures. Depending on the requirements, you can output the log file without BOM / header and then combine it with the BOM / header with a script.
Recommended Posts