Skip to content

Commit

Permalink
Merge pull request #62 from JNU-econovation/log_writer_json
Browse files Browse the repository at this point in the history
Log writer 기능 추가 및 보수
  • Loading branch information
inferior3x authored Nov 29, 2024
2 parents 806e869 + 680ccc9 commit 5d228f3
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 115 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.whoz_in.log_writer;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class TimeLogger {
@Scheduled(fixedDelay = 60000, timeUnit = TimeUnit.MINUTES)
public void log(){
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.whoz_in.log_writer.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.whoz_in.log_writer.managed.ManagedInfo;
import com.whoz_in.log_writer.monitor.MonitorInfo;
import java.io.IOException;
import java.util.List;
import java.util.Map;
Expand All @@ -11,61 +13,81 @@
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;

//실행시킬 프로세스들이 필요로 하는 정보를 제공하는 역할을 한다.
//이를 위해 network-<profile>.json에서 설정값을 가져오며, 올바른 값인지 검증한다.
@Getter
@Component
public class NetworkConfig {
// Getters and setters
private final Map<String, String> ssidInfo; //k: name, v: ssid
private final Monitor monitor;
private final List<Managed> mdnsList;
private final List<Managed> arpList;
private final MonitorInfo monitorInfo;
private final List<ManagedInfo> mdnsList;
private final List<ManagedInfo> arpList;

@SuppressWarnings("unchecked")
public NetworkConfig(@Value("${spring.profiles.active:default}") String profile, ResourceLoader loader, ObjectMapper mapper) {
Resource resource = loader.getResource("classpath:/network-%s.json".formatted(profile));
String jsonPath = "classpath:/network-%s.json".formatted(profile);
Resource resource = loader.getResource(jsonPath);
Map<String, Object> map;

try {
//JSON 파일 읽기
Map<String, Object> map = mapper.readValue(resource.getFile(), Map.class);
map = mapper.readValue(resource.getFile(), Map.class); //JSON 파일 읽기
} catch (IOException e) {
throw new RuntimeException(jsonPath + " 로드 실패");
}

try {
//interface_info
List<Map<String, String>> interfaceInfoList = (List<Map<String, String>>) map.get("ssid_info");
List<Map<String, String>> interfaceInfoList = (List<Map<String, String>>) map.get(
"ssid_info");
this.ssidInfo = interfaceInfoList.stream()
.collect(Collectors.toMap(info-> info.get("name"), info->info.get("ssid")));

.collect(Collectors.toMap(info -> info.get("name"), info -> info.get("ssid")));
//monitor
Map<String, String> monitorMap = (Map<String, String>) map.get("monitor");
this.monitor = new Monitor(
this.monitorInfo = new MonitorInfo(
monitorMap.get("interface"),
generateCommand(monitorMap.get("command"), monitorMap.get("interface"))
);

// managed
Map<String, Object> managedMap = (Map<String, Object>) map.get("managed");

// mdns
Map<String, Object> mdnsMap = (Map<String, Object>) managedMap.get("mdns");
String mdnsCommand = (String) mdnsMap.get("command");
this.mdnsList = ((List<String>) mdnsMap.get("interfaces")).stream()
.map(interfaceName->new Managed(interfaceName, ssidInfo.get(interfaceName), generateCommand(mdnsCommand, interfaceName)))
.map(interfaceName -> new ManagedInfo(interfaceName,
ssidInfo.get(interfaceName),
generateCommand(mdnsCommand, interfaceName)))
.toList();

// arp
Map<String, Object> arpMap = (Map<String, Object>) managedMap.get("arp");
String arpCommand = (String) arpMap.get("command");
this.arpList = ((List<String>) arpMap.get("interfaces")).stream()
.map(interfaceName->new Managed(interfaceName, ssidInfo.get(interfaceName), generateCommand(arpCommand, interfaceName)))
.map(interfaceName -> new ManagedInfo(interfaceName,
ssidInfo.get(interfaceName),
generateCommand(arpCommand, interfaceName)))
.toList();

} catch (IOException e) {
throw new RuntimeException("Failed to load configuration from JSON file", e);
validate();
} catch (Exception e){
e.printStackTrace();
throw new RuntimeException("network json 구조가 잘못되었음");
}
}

private String generateCommand(String commandTemplate, String interfaceName) {
return commandTemplate.replace("{{interface}}", interfaceName);
}

public record Monitor(String interfaceName, String command) {}
public record Managed(String interfaceName, String ssid, String command) {}
private void validate(){
this.mdnsList.forEach(mdns-> {
if (!ssidInfo.containsKey(mdns.interfaceName()))
throw new IllegalArgumentException("mdns에 정의되지 않은 인터페이스가 있음");
});
this.arpList.forEach(arp-> {
if (!ssidInfo.containsKey(arp.interfaceName()))
throw new IllegalArgumentException("arp에 정의되지 않은 인터페이스가 있음");
});
//TODO: 더 많은 검증
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;

@Configuration
@PropertySources({@PropertySource("classpath:/env.properties")})
@PropertySource("classpath:/env.properties")
public class PropertiesConfig {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.whoz_in.log_writer.managed;

//Managed 프로세스를 생성하고 처리하는 과정에서 필요한 정보를 담는다.
public record ManagedInfo(String interfaceName, String ssid, String command) {}
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
package com.whoz_in.log_writer.managed.arp;

import com.whoz_in.log_writer.managed.ManagedInfo;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

//단발성 프로세스
public final class ArpLogProcess {
public class ArpLogProcess {
private final BufferedReader br;
public ArpLogProcess(String command, String password) {
Process process;
private final Process process;
public ArpLogProcess(ManagedInfo info, String password) {
try {
process = new ProcessBuilder(command.split(" ")).start();
br = new BufferedReader(new InputStreamReader(process.getInputStream()));
//TODO: error 처리 로직 수정
new File("../error").mkdir(); //에러 처리 수정하면 이거 없앨게요..
this.process = new ProcessBuilder(info.command().split(" "))
.redirectError(new File("../error", info.ssid()+".txt")) //이것도..
.start();
this.br = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
bw.write(password);
bw.newLine();
bw.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}

}

//단발성 프로세스로, 프로세스가 종료될 때까지 run은 블로킹된다.
Expand All @@ -42,4 +47,7 @@ public List<String> readLines(){
return logs;
}

public boolean isAlive(){
return process.isAlive();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@


import com.whoz_in.log_writer.config.NetworkConfig;
import com.whoz_in.log_writer.config.NetworkConfig.Managed;
import com.whoz_in.log_writer.managed.ManagedInfo;
import com.whoz_in.log_writer.managed.ManagedLog;
import com.whoz_in.log_writer.managed.ManagedLogDAO;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
Expand All @@ -16,7 +17,7 @@
public class ArpLogWriter {
private final ManagedLogDAO dao;
private final ArpLogParser parser;
private final List<Managed> arpList;
private final List<ManagedInfo> arpList;
private final String sudoPassword;

public ArpLogWriter(ManagedLogDAO dao,
Expand All @@ -30,22 +31,35 @@ public ArpLogWriter(ManagedLogDAO dao,
this.sudoPassword = sudoPassword;
}

@Scheduled(fixedRate = 5000)
@Scheduled(initialDelay = 10000, fixedRate = 5000)
private void scan() {
Set<ManagedLog> logs= arpList.stream()
.flatMap(arp-> {
ArpLogProcess proc = new ArpLogProcess(arp.command(), sudoPassword); //프로세스 실행
List<ManagedLog> logs= arpList.stream()
.flatMap(arpInfo-> {
ArpLogProcess proc = new ArpLogProcess(arpInfo, sudoPassword); //프로세스 실행
List<String> lines = proc.readLines(); //프로세스의 모든 출력 가져오기
return lines.stream() //출력 라인들을 ManagedLog 변환하며 ssid도 넣어줌
Set<ManagedLog> procLogs = lines.stream() //출력 라인들을 ManagedLog 변환하며 ssid도 넣어줌
.filter(parser::validate)
.map(line->{
ManagedLog log = parser.parse(line);
log.setSsid(arp.ssid());
log.setSsid(arpInfo.ssid());
return log;
});
})
.collect(Collectors.toSet()); //Set으로 중복 제거

/*
Arp-scan은 단발성인데
Process의 isAlive()는 실행 중일 때도 false일 수 있고, 종료 중일 때도 true일 수 있으므로 오류의 판단이 힘들다.
따라서 Arp-scan의 경우 무조건 1개 이상의 결과가 나오므로 0개라면 실행 실패라고 판단한다.
*/
if (procLogs.isEmpty()) {
System.err.println("[managed - arp(%s)] 실행 실패 : ERROR".formatted(arpInfo.ssid()));
return Stream.empty();
}
System.out.println("[managed - arp(%s)] 저장할 로그 개수 : %d".formatted(arpInfo.ssid(), procLogs.size()));
return procLogs.stream();
})
.collect(Collectors.toSet()); //Set으로 중복 제거
System.out.println("[managed - arp] 저장할 로그 개수 : " +logs.size());
.toList();

dao.insertAll(logs);
}
}
Original file line number Diff line number Diff line change
@@ -1,38 +1,45 @@
package com.whoz_in.log_writer.managed.mdns;

import com.whoz_in.log_writer.common.util.NonBlockingBufferedReader;
import com.whoz_in.log_writer.managed.ManagedInfo;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;

public final class MdnsLogProcess {
public class MdnsLogProcess {
private final Process process;
private final NonBlockingBufferedReader cbr;

public MdnsLogProcess(String command, String sudoPassword) {
//TODO: Info로 변경
public MdnsLogProcess(ManagedInfo info, String sudoPassword) {
try {
this.process = new ProcessBuilder(command.split(" "))
new File("../error").mkdir(); //에러 처리 수정하면 이거 없앨게요..
this.process = new ProcessBuilder(info.command().split(" "))
.redirectError(new File("../error", info.ssid()+".txt"))
.start();
//TODO: errorStream 로깅 - process.getErrorStream()
this.cbr = new NonBlockingBufferedReader(new BufferedReader(new InputStreamReader(process.getInputStream())));

Writer writer = new OutputStreamWriter(process.getOutputStream());
this.cbr = new NonBlockingBufferedReader(new BufferedReader(new InputStreamReader(this.process.getInputStream())));
Writer writer = new OutputStreamWriter(this.process.getOutputStream());
writer.write(sudoPassword + System.lineSeparator());
writer.flush();
} catch (IOException e) {
throw new RuntimeException(command + " 실행 실패");
throw new RuntimeException(info.command() + " 실행 실패");
}
}

/**
*
* @return 프로세스의 출력에서 한 줄을 읽어들인다.
* 읽을 줄이 없을경우 null을 출력한다.
*/
public String readLine() throws IOException {
return cbr.readLine();
public String readLine(){
//여기서 try catch
try {
return this.cbr.readLine();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public boolean isAlive(){
Expand Down
Loading

0 comments on commit 5d228f3

Please sign in to comment.