Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.airlift.log.LogFileName Maven / Gradle / Ivy
/*
* 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 io.airlift.log;
import com.google.common.base.Splitter;
import com.google.common.collect.ComparisonChain;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.DateTimeException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;
import static com.google.common.base.CharMatcher.anyOf;
import static java.lang.Integer.parseInt;
import static java.util.Objects.requireNonNull;
import static java.util.UUID.randomUUID;
final class LogFileName
implements Comparable
{
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("-yyyyMMdd.HHmmss");
private static final int MAX_GENERATED_INDEX = 1000;
private final String fileName;
private final LocalDateTime dateTime;
private final OptionalInt index;
private final OptionalInt legacyIndex;
private final Optional slug;
private final boolean compressed;
/**
* Attempts to parse a log file name that is part of the history files for the master log file.
*
* New: mainName-yyyyMMdd.HHmmss.compressExtension
* Legacy: mainName-yyyyMMdd.HHmmss-counter.compressExtension
*
* @param masterLogFileName the main file of the logger
* @param historyFileName the history file name to parse
* @return a present value if the file name is part of the history set
*/
public static Optional parseHistoryLogFileName(String masterLogFileName, String historyFileName)
{
requireNonNull(masterLogFileName, "masterLogFileName is null");
requireNonNull(historyFileName, "historyFileName is null");
if (!historyFileName.startsWith(masterLogFileName + "-")) {
return Optional.empty();
}
String remainder = historyFileName.substring(masterLogFileName.length() + 1);
boolean compressed = remainder.endsWith(".gz");
if (compressed) {
remainder = remainder.substring(0, remainder.length() - ".gz".length());
}
if (remainder.isEmpty()) {
// This is not considered a valid log file, because the log should have already been renamed
return Optional.empty();
}
if (remainder.endsWith(".log")) {
return parseLegacyLogName(historyFileName, remainder, compressed);
}
return parseNewLogName(historyFileName, remainder, compressed);
}
private static Optional parseNewLogName(String historyFileName, String remainder, boolean compressed)
{
// yyyyMMdd.HHmmss-counter
List parts = Splitter.on(anyOf(".-")).limit(3).splitToList(remainder);
if (parts.size() < 2) {
return Optional.empty();
}
String date = parts.get(0);
String time = parts.get(1);
if (date.length() != 8 || time.length() != 6) {
return Optional.empty();
}
LocalDateTime dateTime;
try {
dateTime = LocalDateTime.of(
parseInt(date.substring(0, 4)),
parseInt(date.substring(4, 6)),
parseInt(date.substring(6, 8)),
parseInt(time.substring(0, 2)),
parseInt(time.substring(2, 4)),
parseInt(time.substring(4, 6)));
}
catch (NumberFormatException | DateTimeException e) {
return Optional.empty();
}
int index = 0;
Optional slug = Optional.empty();
if (parts.size() == 3) {
try {
index = parseInt(parts.get(2));
}
catch (NumberFormatException ignored) {
slug = Optional.of(parts.get(2));
}
}
return Optional.of(new LogFileName(historyFileName, dateTime, OptionalInt.of(index), OptionalInt.empty(), slug, compressed));
}
private static Optional parseLegacyLogName(String historyFileName, String remainder, boolean compressed)
{
// %d{yyyy-MM-dd}.%i.log
remainder = remainder.substring(0, remainder.length() - ".log".length());
List parts = Splitter.on(anyOf(".-")).limit(4).splitToList(remainder);
if (parts.size() != 4) {
return Optional.empty();
}
LocalDateTime dateTime;
try {
dateTime = LocalDateTime.of(parseInt(parts.get(0)), parseInt(parts.get(1)), parseInt(parts.get(2)), 0, 0);
}
catch (NumberFormatException | DateTimeException e) {
return Optional.empty();
}
int legacyIndex = -1;
Optional slug = Optional.empty();
try {
legacyIndex = parseInt(parts.get(3));
}
catch (NumberFormatException ignored) {
slug = Optional.of(parts.get(3));
}
return Optional.of(new LogFileName(historyFileName, dateTime, OptionalInt.empty(), OptionalInt.of(legacyIndex), slug, compressed));
}
public static LogFileName generateNextLogFileName(Path masterLogFile, Optional compressionExtension)
{
LocalDateTime dateTime = LocalDateTime.now().withNano(0);
String suffix = DATE_TIME_FORMATTER.format(dateTime);
for (int index = 0; index < MAX_GENERATED_INDEX; index++) {
String newFileName = masterLogFile.getFileName() + suffix + (index > 0 ? "-" + index : "");
Path newFile = masterLogFile.resolveSibling(newFileName);
if (!fileAlreadyExists(newFile, compressionExtension)) {
return new LogFileName(newFileName, dateTime, OptionalInt.of(index), OptionalInt.empty(), Optional.empty(), false);
}
}
// something strange is happening, just use a random UUID, so we continue logging
String slug = randomUUID().toString();
String randomFileName = masterLogFile.getFileName() + suffix + "--" + slug;
return new LogFileName(randomFileName, dateTime, OptionalInt.of(0), OptionalInt.empty(), Optional.of(slug), false);
}
private static boolean fileAlreadyExists(Path newFile, Optional compressionExtension)
{
return Files.exists(newFile) ||
compressionExtension
.map(extension -> newFile.resolveSibling(newFile.getFileName() + extension))
.map(Files::exists)
.orElse(false);
}
private LogFileName(String fileName, LocalDateTime dateTime, OptionalInt index, OptionalInt legacyIndex, Optional slug, boolean compressed)
{
this.fileName = requireNonNull(fileName, "fileName is null");
this.dateTime = requireNonNull(dateTime, "dateTime is null");
this.index = requireNonNull(index, "index is null");
this.legacyIndex = requireNonNull(legacyIndex, "legacyIndex is null");
this.slug = requireNonNull(slug, "slug is null");
this.compressed = compressed;
}
public String getFileName()
{
return fileName;
}
public LocalDateTime getDateTime()
{
return dateTime;
}
public OptionalInt getIndex()
{
return index;
}
public OptionalInt getLegacyIndex()
{
return legacyIndex;
}
public Optional getSlug()
{
return slug;
}
public boolean isCompressed()
{
return compressed;
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LogFileName that = (LogFileName) o;
return dateTime.equals(that.dateTime) &&
index.equals(that.index) &&
legacyIndex.equals(that.legacyIndex) &&
slug.equals(that.slug);
}
@Override
public int hashCode()
{
return Objects.hash(dateTime, index, legacyIndex, slug);
}
@Override
public int compareTo(LogFileName o)
{
return ComparisonChain.start()
.compare(dateTime, o.dateTime)
.compareTrueFirst(index.isPresent(), o.index.isPresent())
.compare(index.orElse(0), o.index.orElse(0))
.compareTrueFirst(legacyIndex.isPresent(), o.legacyIndex.isPresent())
.compare(-legacyIndex.orElse(0), -o.legacyIndex.orElse(0))
.compareFalseFirst(slug.isPresent(), o.slug.isPresent())
.compare(slug.orElse(""), o.slug.orElse(""))
.result();
}
@Override
public String toString()
{
return fileName;
}
public LogFileName withCompression(Path compressedFile)
{
return new LogFileName(compressedFile.getFileName().toString(), dateTime, index, legacyIndex, slug, true);
}
}