本文目录导读:

我来为你提供几个Java日志检索的完整案例实现。
基础日志文件检索
1 按关键词搜索
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.regex.*;
public class LogSearcher {
/**
* 在单个日志文件中搜索关键词
*/
public static List<String> searchInFile(String filePath, String keyword) throws IOException {
List<String> results = new ArrayList<>();
Path path = Paths.get(filePath);
try (Stream<String> lines = Files.lines(path)) {
lines.filter(line -> line.contains(keyword))
.forEach(results::add);
}
return results;
}
/**
* 在多个日志文件中搜索
*/
public static Map<String, List<String>> searchInFiles(List<String> filePaths, String keyword) {
Map<String, List<String>> results = new HashMap<>();
for (String filePath : filePaths) {
try {
List<String> matches = searchInFile(filePath, keyword);
if (!matches.isEmpty()) {
results.put(filePath, matches);
}
} catch (IOException e) {
System.err.println("Error reading file: " + filePath);
}
}
return results;
}
}
2 带时间范围的检索
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.*;
public class TimeBasedLogSearcher {
private static final DateTimeFormatter LOG_DATE_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/**
* 按时间范围检索日志
*/
public static List<String> searchByTimeRange(String filePath,
LocalDateTime startTime,
LocalDateTime endTime) throws IOException {
List<String> results = new ArrayList<>();
Pattern timePattern = Pattern.compile("(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})");
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
Matcher matcher = timePattern.matcher(line);
if (matcher.find()) {
LocalDateTime logTime = LocalDateTime.parse(matcher.group(1), LOG_DATE_FORMAT);
if (!logTime.isBefore(startTime) && !logTime.isAfter(endTime)) {
results.add(line);
}
}
}
}
return results;
}
}
高级日志检索系统
1 完整的日志检索服务
import java.io.*;
import java.nio.file.*;
import java.time.*;
import java.time.format.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;
import java.util.stream.*;
public class AdvancedLogSearchService {
private final Path logDirectory;
private final ExecutorService executor;
public AdvancedLogSearchService(String logDirectory) {
this.logDirectory = Paths.get(logDirectory);
this.executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
}
/**
* 综合日志检索
*/
public LogSearchResult search(LogSearchCriteria criteria) throws IOException, InterruptedException {
List<Path> logFiles = findLogFiles(criteria);
List<Future<List<LogEntry>>> futures = new ArrayList<>();
for (Path logFile : logFiles) {
futures.add(executor.submit(() -> searchInFile(logFile, criteria)));
}
LogSearchResult result = new LogSearchResult(criteria);
for (Future<List<LogEntry>> future : futures) {
result.addEntries(future.get());
}
return result;
}
private List<Path> findLogFiles(LogSearchCriteria criteria) throws IOException {
try (Stream<Path> stream = Files.walk(logDirectory)) {
return stream
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(".log"))
.filter(path -> {
if (criteria.getFilePattern() == null) return true;
return path.getFileName().toString().matches(criteria.getFilePattern());
})
.collect(Collectors.toList());
}
}
private List<LogEntry> searchInFile(Path filePath, LogSearchCriteria criteria) {
List<LogEntry> entries = new ArrayList<>();
try (BufferedReader reader = Files.newBufferedReader(filePath)) {
String line;
int lineNumber = 0;
while ((line = reader.readLine()) != null) {
lineNumber++;
LogEntry entry = parseLogEntry(filePath, line, lineNumber);
if (matchesCriteria(entry, criteria)) {
entries.add(entry);
}
}
} catch (IOException e) {
System.err.println("Error reading file: " + filePath);
}
return entries;
}
private LogEntry parseLogEntry(Path filePath, String line, int lineNumber) {
LogEntry entry = new LogEntry();
entry.setFilePath(filePath.toString());
entry.setLineNumber(lineNumber);
entry.setRawLine(line);
// 解析日志级别
Pattern levelPattern = Pattern.compile("\\b(ERROR|WARN|INFO|DEBUG|TRACE)\\b");
Matcher levelMatcher = levelPattern.matcher(line);
if (levelMatcher.find()) {
entry.setLevel(LogLevel.valueOf(levelMatcher.group(1)));
}
// 解析时间戳
Pattern timePattern = Pattern.compile("(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}[.,]\\d{3})");
Matcher timeMatcher = timePattern.matcher(line);
if (timeMatcher.find()) {
try {
entry.setTimestamp(LocalDateTime.parse(
timeMatcher.group(1).replace(",", "."),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")
));
} catch (Exception e) {
// 时间解析失败,忽略
}
}
// 解析异常信息
if (line.contains("Exception") || line.contains("Error")) {
extractExceptionInfo(entry, line);
}
return entry;
}
private void extractExceptionInfo(LogEntry entry, String line) {
Pattern exceptionPattern = Pattern.compile("(\\w+\\.\\w+(?:\\.\\w+)*Exception|\\w+Error)");
Matcher matcher = exceptionPattern.matcher(line);
if (matcher.find()) {
entry.setExceptionType(matcher.group(1));
}
}
private boolean matchesCriteria(LogEntry entry, LogSearchCriteria criteria) {
if (criteria.getLevel() != null && entry.getLevel() != criteria.getLevel()) {
return false;
}
if (criteria.getKeyword() != null &&
!entry.getRawLine().toLowerCase().contains(criteria.getKeyword().toLowerCase())) {
return false;
}
if (criteria.getStartTime() != null && entry.getTimestamp() != null) {
if (entry.getTimestamp().isBefore(criteria.getStartTime())) {
return false;
}
}
if (criteria.getEndTime() != null && entry.getTimestamp() != null) {
if (entry.getTimestamp().isAfter(criteria.getEndTime())) {
return false;
}
}
if (criteria.getExceptionType() != null && entry.getExceptionType() != null) {
if (!entry.getExceptionType().equals(criteria.getExceptionType())) {
return false;
}
}
return true;
}
public void shutdown() {
executor.shutdown();
}
}
// 日志搜索条件
class LogSearchCriteria {
private String keyword;
private LogLevel level;
private LocalDateTime startTime;
private LocalDateTime endTime;
private String filePattern;
private String exceptionType;
// Getters and setters
// ...
}
// 日志条目
class LogEntry {
private String filePath;
private int lineNumber;
private LocalDateTime timestamp;
private LogLevel level;
private String rawLine;
private String exceptionType;
private String threadName;
private String className;
// Getters and setters
// ...
}
// 日志级别枚举
enum LogLevel {
TRACE, DEBUG, INFO, WARN, ERROR, FATAL
}
// 搜索结果
class LogSearchResult {
private LogSearchCriteria criteria;
private List<LogEntry> entries = new ArrayList<>();
private long searchTime;
public LogSearchResult(LogSearchCriteria criteria) {
this.criteria = criteria;
}
public void addEntries(List<LogEntry> entries) {
this.entries.addAll(entries);
}
public void addEntry(LogEntry entry) {
this.entries.add(entry);
}
public List<LogEntry> getEntries() {
return entries;
}
public int getTotalCount() {
return entries.size();
}
// Getters and setters
// ...
}
2 日志索引优化
import java.util.concurrent.ConcurrentHashMap;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class LogIndexer {
private final Map<String, List<LogIndex>> indexCache = new ConcurrentHashMap<>();
/**
* 创建日志索引
*/
public void createIndex(String filePath) throws IOException {
List<LogIndex> indices = new ArrayList<>();
try (RandomAccessFile file = new RandomAccessFile(filePath, "r");
FileChannel channel = file.getChannel()) {
MappedByteBuffer buffer = channel.map(
FileChannel.MapMode.READ_ONLY, 0, channel.size());
long position = 0;
int lineNumber = 0;
StringBuilder line = new StringBuilder();
while (buffer.hasRemaining()) {
byte b = buffer.get();
if (b == '\n') {
processLine(filePath, line.toString(), position, lineNumber++, indices);
position = buffer.position();
line.setLength(0);
} else {
line.append((char) b);
}
}
}
indexCache.put(filePath, indices);
}
private void processLine(String filePath, String line, long position,
int lineNumber, List<LogIndex> indices) {
LogIndex index = new LogIndex();
index.setFilePath(filePath);
index.setPosition(position);
index.setLineNumber(lineNumber);
index.setLength(line.length());
// 提取关键词
extractKeywords(line, index);
indices.add(index);
}
private void extractKeywords(String line, LogIndex index) {
// 提取时间、级别、异常等关键信息
Pattern pattern = Pattern.compile(
"(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}[.,]\\d{3})\\s+" +
"(ERROR|WARN|INFO|DEBUG|TRACE)\\s+");
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
index.setTimestamp(matcher.group(1));
index.setLevel(matcher.group(2));
}
}
/**
* 使用索引快速检索
*/
public List<String> searchByIndex(String filePath, String keyword) throws IOException {
List<String> results = new ArrayList<>();
List<LogIndex> indices = indexCache.get(filePath);
if (indices == null) {
createIndex(filePath);
indices = indexCache.get(filePath);
}
try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) {
for (LogIndex index : indices) {
// 快速定位并读取日志行
file.seek(index.getPosition());
String line = file.readLine();
if (line != null && line.contains(keyword)) {
results.add(line);
}
}
}
return results;
}
}
class LogIndex {
private String filePath;
private long position;
private int lineNumber;
private int length;
private String timestamp;
private String level;
// Getters and setters
// ...
}
3 使用示例
public class LogSearchDemo {
public static void main(String[] args) {
// 基础使用
basicSearch();
// 高级使用
advancedSearch();
// 索引优化使用
indexedSearch();
}
private static void basicSearch() {
try {
// 单文件搜索
List<String> results = LogSearcher.searchInFile(
"/var/log/application.log", "NullPointerException");
results.forEach(System.out::println);
// 多文件搜索
Map<String, List<String>> allResults = LogSearcher.searchInFiles(
Arrays.asList("/var/log/app1.log", "/var/log/app2.log"),
"ERROR");
allResults.forEach((file, matches) -> {
System.out.println("File: " + file);
matches.forEach(line -> System.out.println(" " + line));
});
} catch (IOException e) {
e.printStackTrace();
}
}
private static void advancedSearch() {
AdvancedLogSearchService searchService =
new AdvancedLogSearchService("/var/log/myapp");
try {
// 创建搜索条件
LogSearchCriteria criteria = new LogSearchCriteria();
criteria.setKeyword("NullPointerException");
criteria.setLevel(LogLevel.ERROR);
criteria.setStartTime(LocalDateTime.now().minusHours(24));
criteria.setEndTime(LocalDateTime.now());
criteria.setFilePattern("application.*\\.log");
// 执行搜索
LogSearchResult result = searchService.search(criteria);
// 输出结果
System.out.println("Total matches: " + result.getTotalCount());
result.getEntries().forEach(entry -> {
System.out.printf("[%s] %s:%d - %s%n",
entry.getTimestamp(),
entry.getFilePath(),
entry.getLineNumber(),
entry.getRawLine());
});
} catch (Exception e) {
e.printStackTrace();
} finally {
searchService.shutdown();
}
}
private static void indexedSearch() {
LogIndexer indexer = new LogIndexer();
try {
// 使用索引搜索(首次会创建索引)
List<String> results = indexer.searchByIndex(
"/var/log/large-application.log", "OutOfMemoryError");
results.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
}
性能优化建议
1 多线程搜索
public CompletableFuture<List<LogEntry>> parallelSearch(
List<Path> files, LogSearchCriteria criteria) {
List<CompletableFuture<List<LogEntry>>> futures = files.stream()
.map(file -> CompletableFuture.supplyAsync(() -> {
try {
return searchInFile(file, criteria);
} catch (Exception e) {
return Collections.emptyList();
}
}))
.collect(Collectors.toList());
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApply(v -> futures.stream()
.flatMap(future -> future.join().stream())
.collect(Collectors.toList()));
}
2 内存映射文件
public void searchWithMemoryMappedFile(String filePath, String keyword)
throws IOException {
try (RandomAccessFile file = new RandomAccessFile(filePath, "r");
FileChannel channel = file.getChannel()) {
MappedByteBuffer buffer = channel.map(
FileChannel.MapMode.READ_ONLY, 0, channel.size());
int bufferSize = 1024 * 1024; // 1MB缓冲区
byte[] chunk = new byte[bufferSize];
while (buffer.hasRemaining()) {
int bytesToRead = Math.min(buffer.remaining(), bufferSize);
buffer.get(chunk, 0, bytesToRead);
String content = new String(chunk, 0, bytesToRead);
if (content.contains(keyword)) {
// 处理匹配的内容
System.out.println("Found match at position: " + buffer.position());
}
}
}
}
3 缓存优化
public class CachedLogSearcher {
private final Cache<String, List<String>> searchCache;
private final Cache<String, List<LogIndex>> indexCache;
public CachedLogSearcher() {
// 使用Caffeine缓存
this.searchCache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
this.indexCache = Caffeine.newBuilder()
.maximumSize(100)
.expireAfterAccess(1, TimeUnit.HOURS)
.build();
}
public List<String> search(String filePath, String keyword) {
String cacheKey = filePath + "::" + keyword;
return searchCache.get(cacheKey, k -> {
try {
return performSearch(filePath, keyword);
} catch (IOException e) {
return Collections.emptyList();
}
});
}
}
这个日志检索案例实现了:
- 基础关键词搜索
- 时间范围过滤
- 多条件组合搜索
- 多线程并行处理
- 日志索引优化
- 缓存机制
你可以根据实际需求选择合适的实现方式,并在此基础上进行扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播