- This project uses
- Maven 3.6+
- Java 8
- Spring boot
- MySQL
- Mockito
mysql> use test;
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| log_details |
+----------------+
1 row in set (0.22 sec)
mysql> select * from log_details;
+----+-------+----------------+------------+
| id | alert | event_duration | event_id |
+----+-------+----------------+------------+
| 1 | false | 3ms | scsmbstgrb |
| 2 | true | 8ms | scsmbstgrc |
+----+-------+----------------+------------+
2 rows in set (0.02 sec)
mysql>
LogExecutorService.java
@Service
@Slf4j
public class LogExecutorService {
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
@Autowired
private LogDetailsRepository repository;
public void readLogFile(String filename) throws IOException {
ExecutorService service = Executors.newFixedThreadPool(10);
List<LogDetails> loggersData = getLogDetailsFromFile(filename);
Future<Integer> future = service.submit(new LogProcessor(repository,loggersData));
try {
System.out.println("Result of the operation is: " + future.get());
} catch (InterruptedException | ExecutionException e) {
log.error("LogExecutorService | readLogFile | Exception occurred = {}", e);
e.printStackTrace();
}
}
private List<LogDetails> getLogDetailsFromFile(String fileName) throws IOException {
List<LogDetailsDto> loggersData = new ArrayList<>();
// Reads text from a character-input stream, buffering characters so as to provide for the efficient reading of
// characters, arrays, and lines.
try (BufferedReader reader = new BufferedReader(new FileReader(new File(fileName)))) {
String line = null;
while ((line = reader.readLine()) != null) {
loggersData.add(this.objectMapper().readValue(line, LogDetailsDto.class));
}
} catch (FileNotFoundException ex) {
log.error("LogExecutorService | getLogDetailsFromFile | File is missing {}", ex);
} catch (IOException ex) {
log.error("LogExecutorService | getLogDetailsFromFile | IOException= {}", ex);
}
// Sort based on Time-stamp and then group based on Id
Map<String, List<LogDetailsDto>> logDetailsMap = loggersData.stream()
.filter(e -> e.getType() == null && e.getHost() == null)
.sorted(Comparator.comparing(LogDetailsDto::getTimestamp).reversed())
.collect(Collectors.groupingBy(LogDetailsDto::getId));
List<LogDetails> details = new ArrayList<>();
for( Entry<String, List<LogDetailsDto>> entry : logDetailsMap.entrySet()) {
// Get the Duration details only
List<Long> diff = entry.getValue().stream().map(e -> e.getTimestamp()).collect(Collectors.toList());
long duration = getData(diff);
details.add(LogDetails.builder()
.eventId(entry.getValue().stream().map(e -> e.getId()).findFirst().get())
.eventDuration(duration+"ms")
.alert(getData(diff) > 4 ? "true" : "false")
.build());
}
return details;
}
// Used BigDecimal which works nicely with complex long
public static long getData(List<Long> diff) {
long[] array = diff.stream().mapToLong(Long::valueOf).toArray();
if(array.length == 2) {
BigDecimal bd1 = new BigDecimal(array[0]);
BigDecimal bd2 = new BigDecimal(array[1]);
return bd1.subtract(bd2).longValue();
}
return 0;
}
}
LogProcessor.java
@Service
public class LogProcessor implements Callable<Integer> {
private LogDetailsRepository logDetailsRepository;
private List<LogDetails> logDetails;
public LogProcessor() {
}
public LogProcessor(LogDetailsRepository logDetailsRepository, List<LogDetails> loggersData) {
this.logDetailsRepository = logDetailsRepository;
this.logDetails = loggersData;
}
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + " processing record for : " + logDetails);
logDetailsRepository.saveAll(logDetails);
return 1;
}
}
LogDetailsRepository.java
@Repository
public interface LogDetailsRepository extends JpaRepository<LogDetails, String> {
}
LogDetails
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@Entity
public class LogDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String eventId;
private String eventDuration;
private String alert;
}
LogDetailsDto.java
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@JsonIgnoreProperties(ignoreUnknown = true)
public class LogDetailsDto {
private String id;
private String state;
private long timestamp;
private String type;
private String host;
}
application.properties
spring.datasource.url= jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database = MYSQL
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = create
spring.jpa.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
# Adjust it as per need
spring.jpa.hibernate.jdbc.batch_size=200