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

Dynamic simulation logs #314

Merged
merged 23 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
uses: actions/checkout@v1
with:
repository: powsybl/powsybl-core
ref: refs/heads/main
ref: refs/tags/v6.1.0

- name: Checkout sources
uses: actions/checkout@v1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright (c) 2023, RTE (http://www.rte-france.com/)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.dynawo.commons;

import com.powsybl.commons.PowsyblException;
import com.univocity.parsers.common.ParsingContext;
import com.univocity.parsers.common.ResultIterator;
import com.univocity.parsers.csv.CsvParser;
import com.univocity.parsers.csv.CsvParserSettings;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;

/**
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
*/
public abstract class AbstractCsvParser<T> {

protected static final char DEFAULT_SEPARATOR = '|';

private final char separator;

protected AbstractCsvParser(char separator) {
this.separator = separator;
}

public List<T> parse(Path file) {
if (!Files.exists(file)) {
return Collections.emptyList();
}

try (BufferedReader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
return parse(reader);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

private List<T> parse(BufferedReader reader) {
Objects.requireNonNull(reader);
CsvParserSettings settings = new CsvParserSettings();
settings.getFormat().setDelimiter(separator);
settings.getFormat().setQuoteEscape('"');
settings.getFormat().setLineSeparator(System.lineSeparator());
settings.setMaxColumns(getNbColumns());
CsvParser csvParser = new CsvParser(settings);
ResultIterator<String[], ParsingContext> iterator = csvParser.iterate(reader).iterator();
return read(iterator);
}

protected List<T> read(ResultIterator<String[], ParsingContext> iterator) {
List<T> logs = new ArrayList<>();
int iLine = 0;
while (iterator.hasNext()) {
iLine++;
String[] tokens = iterator.next();
if (!hasCorrectNbColumns(tokens.length)) {
throw new PowsyblException("Columns of line " + iLine + " are inconsistent");
}
createEntry(tokens).ifPresent(logs::add);
}
return logs;
}

protected abstract Optional<T> createEntry(String[] tokens);

protected abstract boolean hasCorrectNbColumns(int tokensSize);

protected abstract int getNbColumns();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2023, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.dynawo.commons;

import com.powsybl.commons.reporter.Report;
import com.powsybl.commons.reporter.Reporter;
import com.powsybl.commons.reporter.TypedValue;
import com.powsybl.dynawo.commons.dynawologs.LogEntry;
import com.powsybl.dynawo.commons.timeline.TimelineEntry;

/**
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
*/
public final class CommonReports {

private static final String TIME_MS = "timeMsTypedValue";
private static final String ID = "idTypedValue";

private CommonReports() {
}

public static Reporter createDynawoLogReporter(Reporter reporter) {
return reporter.createSubReporter("dynawoLog",
"Dynawo Log");
}

public static void reportTimelineEvent(Reporter reporter, TimelineEntry timelineEntry) {
reporter.report(Report.builder()
.withKey("DynawoTimelineEvent")
.withDefaultMessage("[t=${time}] ${message} on equipment '${identifiableId}'")
.withTypedValue("time", timelineEntry.time(), TIME_MS)
.withTypedValue("identifiableId", timelineEntry.modelName(), ID)
.withValue("message", timelineEntry.message())
.withSeverity(TypedValue.TRACE_SEVERITY)
.build());
}

public static void reportLogEvent(Reporter reporter, LogEntry logEntry) {
reporter.report(Report.builder()
.withKey("DynawoTimelineEvent")
.withDefaultMessage("${message}")
.withValue("message", logEntry.message())
.withSeverity(logEntry.severity())
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ private DynawoConstants() {

public static final String DYNAWO_CMD_NAME = "dynawo";

public static final String DYNAWO_TIMELINE_FOLDER = "timeLine";

public static final DynawoVersion VERSION_MIN = new DynawoVersion(1, 5, 0);

public static final List<String> IIDM_EXTENSIONS = List.of(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2023, RTE (http://www.rte-france.com/)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.dynawo.commons.dynawologs;

import com.powsybl.dynawo.commons.AbstractCsvParser;

import java.util.Optional;

/**
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
*/
public final class CsvLogParser extends AbstractCsvParser<LogEntry> {

private static final int NB_COLUMNS = 4;

public CsvLogParser() {
this(DEFAULT_SEPARATOR);
}

public CsvLogParser(char separator) {
super(separator);
}

@Override
protected Optional<LogEntry> createEntry(String[] tokens) {
return tokens.length == NB_COLUMNS ? LogUtils.createLog(tokens[1], tokens[2] + " " + tokens[3])
: LogUtils.createLog(tokens[1], tokens[2]);
}

@Override
protected boolean hasCorrectNbColumns(int tokensSize) {
return tokensSize == NB_COLUMNS - 1 || tokensSize == NB_COLUMNS;
}

@Override
protected int getNbColumns() {
return NB_COLUMNS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Copyright (c) 2023, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.dynawo.commons.dynawologs;

import com.powsybl.commons.reporter.TypedValue;

/**
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
*/
public record LogEntry(TypedValue severity, String message) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2023, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.dynawo.commons.dynawologs;

import com.powsybl.commons.reporter.TypedValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Optional;

/**
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
*/
public final class LogUtils {

private static final Logger LOGGER = LoggerFactory.getLogger(LogUtils.class);
private static final String EMPTY_START = "======";
private static final String EMPTY_BREAKER = "------";

private LogUtils() {
}

public static Optional<LogEntry> createLog(String severity, String message) {
if (severity == null) {
LOGGER.warn("Inconsistent log entry (modelName: '{}', message: '{}')", severity, message);
} else {
if (emptyMessage(message)) {
LOGGER.debug("Empty message, the entry will be skipped : {}", message);
} else {
return convertDynawoLog(severity).map(severityTypedValue -> new LogEntry(severityTypedValue, message));
}
}
return Optional.empty();
}

private static Optional<TypedValue> convertDynawoLog(String severity) {
return switch (severity) {
case "DEBUG" -> Optional.of(TypedValue.DEBUG_SEVERITY);
case "INFO" -> Optional.of(TypedValue.INFO_SEVERITY);
case "WARN" -> Optional.of(TypedValue.WARN_SEVERITY);
case "ERROR" -> Optional.of(TypedValue.ERROR_SEVERITY);
default -> {
LOGGER.warn("Inconsistent severity entry '{}'", severity);
yield Optional.empty();
}
};
}

private static boolean emptyMessage(String message) {
return message == null || message.startsWith(EMPTY_BREAKER) || message.startsWith(EMPTY_START);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,80 +7,37 @@
*/
package com.powsybl.dynawo.commons.timeline;

import com.powsybl.commons.PowsyblException;
import com.univocity.parsers.common.ParsingContext;
import com.univocity.parsers.common.ResultIterator;
import com.univocity.parsers.csv.CsvParser;
import com.univocity.parsers.csv.CsvParserSettings;
import com.powsybl.dynawo.commons.AbstractCsvParser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
*/
public final class CsvTimeLineParser implements TimeLineParser {
public final class CsvTimeLineParser extends AbstractCsvParser<TimelineEntry> implements TimeLineParser {

private static final int NB_COLUMNS = 3;
private final char separator;

public CsvTimeLineParser() {
this('|');
this(DEFAULT_SEPARATOR);
}

public CsvTimeLineParser(char separator) {
this.separator = separator;
super(separator);
}

public List<TimelineEntry> parse(Path file) {
return parse(file, separator);
@Override
protected Optional<TimelineEntry> createEntry(String[] tokens) {
return TimeLineUtil.createEvent(tokens[0], tokens[1], tokens[2]);
}

public static List<TimelineEntry> parse(Path file, char separator) {
if (!Files.exists(file)) {
return Collections.emptyList();
}

try (BufferedReader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
return parse(reader, separator);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

static List<TimelineEntry> parse(BufferedReader reader, char separator) {
Objects.requireNonNull(reader);
CsvParserSettings settings = new CsvParserSettings();
settings.getFormat().setDelimiter(separator);
settings.getFormat().setQuoteEscape('"');
settings.getFormat().setLineSeparator(System.lineSeparator());
settings.setMaxColumns(NB_COLUMNS);
CsvParser csvParser = new CsvParser(settings);
ResultIterator<String[], ParsingContext> iterator = csvParser.iterate(reader).iterator();
return read(iterator);
@Override
protected boolean hasCorrectNbColumns(int tokensSize) {
return NB_COLUMNS == tokensSize;
}

static List<TimelineEntry> read(ResultIterator<String[], ParsingContext> iterator) {
List<TimelineEntry> timeline = new ArrayList<>();
int iLine = 0;
while (iterator.hasNext()) {
iLine++;
String[] tokens = iterator.next();
if (tokens.length != NB_COLUMNS) {
throw new PowsyblException("Columns of line " + iLine + " are inconsistent");
}
TimeLineUtil.createEvent(tokens[0], tokens[1], tokens[2])
.ifPresent(timeline::add);
}
return timeline;
@Override
protected int getNbColumns() {
return NB_COLUMNS;
}

}
Loading
Loading