Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Проект №3 #8

Merged
merged 6 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions logs/dir/log3.txt

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions logs/log1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
11.71.87.42 - - [23/Sep/2023:06:10:36 +0000] "GET /multi-state/orchestration.png HTTP/1.1" 400 38 "-" "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_8_5) AppleWebKit/5312 (KHTML, like Gecko) Chrome/39.0.812.0 Mobile Safari/5312"
141.96.175.104 - - [25/Sep/2023:06:10:36 +0000] "GET /architecture/attitude-oriented/success/Cross-platform-neutral.css HTTP/1.1" 200 2134 "-" "Mozilla/5.0 (Macintosh; PPC Mac OS X 10_5_9) AppleWebKit/5321 (KHTML, like Gecko) Chrome/39.0.800.0 Mobile Safari/5321"
165.138.198.30 - - [27/Sep/2023:06:10:36 +0000] "GET /info-mediaries.php HTTP/1.1" 200 2778 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_6 rv:4.0; en-US) AppleWebKit/533.42.6 (KHTML, like Gecko) Version/4.0 Safari/533.42.6"
185.253.246.248 - - [30/Sep/2023:06:10:36 +0000] "GET /Focused-encoding.svg HTTP/1.1" 200 2468 "-" "Mozilla/5.0 (Windows; U; Windows NT 4.0) AppleWebKit/532.48.2 (KHTML, like Gecko) Version/4.2 Safari/532.48.2"
204.196.83.88 - - [02/Oct/2023:06:10:36 +0000] "PUT /Future-proofed/Customer-focused/Upgradable/internet%20solution_Re-contextualized.css HTTP/1.1" 200 992 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/5360 (KHTML, like Gecko) Chrome/38.0.850.0 Mobile Safari/5360"
72.153.133.99 - - [05/Oct/2023:06:10:36 +0000] "GET /exuding-Secured/contingency%20Future-proofed.css HTTP/1.1" 200 2024 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2 rv:3.0) Gecko/1969-17-05 Firefox/35.0"
72.153.133.97 - - [07/Oct/2023:06:10:36 +0000] "GET /exuding-Secured/contingency%20Future-proofed.css HTTP/1.1" 200 2024 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2 rv:3.0) Gecko/1969-17-05 Firefox/35.0"
82 changes: 82 additions & 0 deletions logs/log2.txt

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@
<type>pom</type>
<scope>import</scope>
</dependency>

<!-- For resolve assertJ`s and mockito`s byte-buddy version conflict -->
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.14.9</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down Expand Up @@ -95,6 +102,24 @@
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.6.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
75 changes: 75 additions & 0 deletions src/main/java/edu/project3/NginxLogAnalyticsApp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package edu.project3;

import edu.project3.argument.Argument;
import edu.project3.argument.Arguments;
import edu.project3.collector.IPsMetricCollector;
import edu.project3.collector.MetadataMetricCollector;
import edu.project3.collector.ResponseCodesMetricCollector;
import edu.project3.collector.ResponseSizesMetricCollector;
import edu.project3.collector.TimeOfDayMetricCollector;
import edu.project3.collector.TopResourcesMetricCollector;
import edu.project3.log.BaseNginxLogParser;
import edu.project3.model.BasicConfiguration;
import edu.project3.source.LocalFilesLogSource;
import edu.project3.source.LogSource;
import edu.project3.source.UrlLogSource;
import edu.project3.utils.BasicConfigurationParser;
import edu.project3.writer.ConsoleMetricsWriter;
import edu.project3.writer.MetricsWriter;
import java.util.List;
import java.util.Map;

public final class NginxLogAnalyticsApp {
private final List<String> commandLineArguments;
private final MetricsWriter writer;

public NginxLogAnalyticsApp(String[] args, MetricsWriter writer) {
commandLineArguments = List.of(args);
this.writer = writer;
}

@SuppressWarnings("checkstyle:UncommentedMain")
public static void main(String[] args) {
new NginxLogAnalyticsApp(args, new ConsoleMetricsWriter()).run();
}

public void run() {
Map<String, String> argumentsMap = parseArguments(commandLineArguments);
BasicConfiguration basicConfiguration = BasicConfigurationParser.parse(argumentsMap);
NginxLogManager manager = createLogManager(basicConfiguration);
writer.print(manager.collect(), basicConfiguration.renderer());
}

private Map<String, String> parseArguments(List<String> args) {
Arguments arguments = new Arguments()
.addArgument(new Argument("path", true))
.addArgument(new Argument("format", false))
.addArgument(new Argument("from", false))
.addArgument(new Argument("to", false));
return arguments.parse(args);
}

private NginxLogManager createLogManager(BasicConfiguration configuration) {
var parser = new BaseNginxLogParser();
LogSource source = createLogSource(configuration);
NginxLogManager manager = new NginxLogManager(source, parser, configuration);
manager.registerMetricCollectors(
new MetadataMetricCollector(),
new TopResourcesMetricCollector(),
new ResponseCodesMetricCollector(),
new IPsMetricCollector(),
new TimeOfDayMetricCollector(),
new ResponseSizesMetricCollector()
);

return manager;
}

private LogSource createLogSource(BasicConfiguration configuration) {
if (configuration.isRemote()) {
return new UrlLogSource(configuration.paths().getFirst());
}
return new LocalFilesLogSource(configuration.paths());
}

}
63 changes: 63 additions & 0 deletions src/main/java/edu/project3/NginxLogManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package edu.project3;

import edu.project3.collector.MetricCollector;
import edu.project3.log.NginxLogParser;
import edu.project3.model.BasicConfiguration;
import edu.project3.model.filter.DateFilter;
import edu.project3.model.filter.LogFilter;
import edu.project3.model.log.LogsContainer;
import edu.project3.model.log.LogsMetadata;
import edu.project3.model.log.NginxLog;
import edu.project3.model.metric.Metric;
import edu.project3.source.LogSource;
import java.util.ArrayList;
import java.util.List;

public class NginxLogManager {
private final LogSource logSource;
private final NginxLogParser parser;
private final BasicConfiguration configuration;
private final List<MetricCollector> collectors = new ArrayList<>();
private final List<LogFilter> filters = new ArrayList<>();

public NginxLogManager(LogSource logSource, NginxLogParser parser, BasicConfiguration configuration) {
this.logSource = logSource;
this.parser = parser;
this.configuration = configuration;
registerLogFilter(new DateFilter(configuration.from(), configuration.to()));
}

public void registerLogFilter(LogFilter filter) {
filters.add(filter);
}

public void registerMetricCollectors(MetricCollector... collector) {
collectors.addAll(List.of(collector));
}

public List<Metric> collect() {
List<NginxLog> logs = applyFilters(obtainLogs());
final LogsContainer container = createContainer(logs);
return collectors.stream().map(collector -> collector.collect(container)).toList();
}

private List<NginxLog> obtainLogs() {
return parser.parse(logSource.getLogs());
}

private List<NginxLog> applyFilters(List<NginxLog> logs) {
List<NginxLog> filteredLogs = logs;
for (LogFilter filter : filters) {
filteredLogs = filteredLogs.stream().filter(filter::isSuitable).toList();
}
return filteredLogs;
}

private LogsContainer createContainer(List<NginxLog> logs) {
return new LogsContainer(
logs,
new LogsMetadata(configuration.paths(), configuration.from(), configuration.to())
);
}

}
4 changes: 4 additions & 0 deletions src/main/java/edu/project3/argument/Argument.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package edu.project3.argument;

public record Argument(String name, boolean isRequired) {
}
31 changes: 31 additions & 0 deletions src/main/java/edu/project3/argument/Arguments.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package edu.project3.argument;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public record Arguments(List<Argument> arguments) {
public Arguments() {
this(new ArrayList<>());
}

public Arguments addArgument(Argument argument) {
arguments.add(argument);
return this;
}

public Map<String, String> parse(List<String> args) {
Map<String, String> argumentsMap = new HashMap<>();
for (Argument argument : arguments) {
int index = args.indexOf("--" + argument.name());
if (index == -1 && argument.isRequired()) {
throw new IllegalArgumentException("Required argument " + argument.name() + " not found");
}
if (index != -1 && index + 1 < args.size()) {
argumentsMap.put(argument.name(), args.get(index + 1));
}
}
return argumentsMap;
}
}
33 changes: 33 additions & 0 deletions src/main/java/edu/project3/collector/IPsMetricCollector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package edu.project3.collector;

import edu.project3.model.log.NginxLog;
import edu.project3.model.metric.components.MetricComponent;
import edu.project3.model.metric.components.MetricTable;
import java.util.Collections;
import java.util.List;

public class IPsMetricCollector extends TopMetricCollector<String> {
public IPsMetricCollector() {
super("IP адреса");
}

@Override
protected List<MetricComponent> createComponents(List<TopElement<String>> topElements) {
final int topCount = 10;
MetricTable table = new MetricTable.ExtendedTableBuilder<TopElement<String>>()
.headers("IP адрес", "Количество")
.rows(topElements)
.stringExtractors(List.of(
TopElement::element,
element -> element.count().toString()
))
.rowsCount(topCount)
.build();
return Collections.singletonList(table);
}

@Override
protected String extractElement(NginxLog log) {
return log.ip();
}
}
41 changes: 41 additions & 0 deletions src/main/java/edu/project3/collector/MetadataMetricCollector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package edu.project3.collector;

import edu.project3.model.log.LogsContainer;
import edu.project3.model.log.NginxLog;
import edu.project3.model.metric.Metric;
import edu.project3.model.metric.components.MetricTable;
import edu.project3.utils.MetricComponentsUtils;
import java.util.List;
import java.util.Locale;

public class MetadataMetricCollector implements MetricCollector {
@Override
public Metric collect(LogsContainer container) {
Metric metric = MetricComponentsUtils.createMetricWithHeader("Общая информация");
metric.components().add(
new MetricTable()
.addHeaders("Метрика", "Значение")
.addRowElements("Файл(-ы)", "`" + String.join(", ", container.metadata().paths()) + "`")
.addRowElements(
"Начальная дата",
container.metadata().from() == null ? "-" : container.metadata().from().toString()
)
.addRowElements(
"Конечная дата",
container.metadata().to() == null ? "-" : container.metadata().to().toString()
)
.addRowElements("Количество запросов", String.valueOf(container.logs().size()))
.addRowElements("Средний размер ответа", getAverageResponseSize(container.logs()))
);
return metric;
}

private String getAverageResponseSize(List<NginxLog> logs) {
return String.format(
Locale.US,
"%.2fb",
logs.stream().map(log -> log.response().bytesSend()).mapToInt(Integer::intValue).average()
.orElse(0)
);
}
}
8 changes: 8 additions & 0 deletions src/main/java/edu/project3/collector/MetricCollector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package edu.project3.collector;

import edu.project3.model.log.LogsContainer;
import edu.project3.model.metric.Metric;

public interface MetricCollector {
Metric collect(LogsContainer container);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package edu.project3.collector;

import edu.project3.model.log.NginxLog;
import edu.project3.model.metric.components.MetricComponent;
import edu.project3.model.metric.components.MetricTable;
import edu.project3.model.remote.HttpStatusCode;
import java.util.Collections;
import java.util.List;

public class ResponseCodesMetricCollector extends TopMetricCollector<Integer> {

public ResponseCodesMetricCollector() {
super("Коды ответа");
}

@Override
protected List<MetricComponent> createComponents(List<TopElement<Integer>> topElements) {
final int topCount = 5;
MetricTable table = new MetricTable.ExtendedTableBuilder<TopElement<Integer>>()
.headers("Код", "Имя", "Количество")
.rows(topElements)
.stringExtractors(List.of(
element -> element.element().toString(),
element -> HttpStatusCode.getByValue(element.element()).getDescription(),
element -> element.count().toString()
))
.rowsCount(topCount)
.build();
return Collections.singletonList(table);
}

@Override
protected Integer extractElement(NginxLog log) {
return log.response().code();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package edu.project3.collector;

import edu.project3.model.log.LogsContainer;
import edu.project3.model.metric.Metric;
import edu.project3.model.metric.components.MetricTable;
import edu.project3.utils.MetricComponentsUtils;
import java.util.Comparator;
import java.util.List;

public class ResponseSizesMetricCollector implements MetricCollector {

@Override
public Metric collect(LogsContainer container) {
Metric metric = MetricComponentsUtils.createMetricWithHeader("Размеры ответов");
List<UrlWithResponseSize> urlWithResponseSizes = container
.logs()
.stream()
.map(log -> new UrlWithResponseSize(log.request().url(), log.response().bytesSend()))
.sorted(Comparator.comparing(UrlWithResponseSize::responseSize).reversed())
.distinct()
.toList();
final int topCount = 5;
MetricTable table = new MetricTable.ExtendedTableBuilder<UrlWithResponseSize>()
.headers("Запрос", "Размер ответа")
.rows(urlWithResponseSizes)
.stringExtractors(List.of(
urlWithResponseSize -> urlWithResponseSize.url,
urlWithResponseSize -> urlWithResponseSize.responseSize.toString()
))
.rowsCount(topCount)
.build();
metric.components().add(table);
return metric;
}

private record UrlWithResponseSize(String url, Integer responseSize) {
}
}
Loading