Skip to content

Commit

Permalink
GH-5027 ShaclSail logging (#5029)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmottestad authored Jun 12, 2024
2 parents b2ddfa0 + 87caad7 commit 516bf0a
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,16 @@
import org.eclipse.rdf4j.sail.shacl.ast.paths.Path;
import org.eclipse.rdf4j.sail.shacl.ast.paths.SimplePath;
import org.eclipse.rdf4j.sail.shacl.results.ValidationResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Håvard Ottestad
*/
abstract class AbstractPairwisePlanNode implements PlanNode {

private static final Logger logger = LoggerFactory.getLogger(AbstractPairwisePlanNode.class);

private final SailConnection connection;
private final Resource[] dataGraph;
private final IRI predicate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.base.CoreDatatype;
import org.eclipse.rdf4j.model.datatypes.XMLDatatypeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Håvard Ottestad
*/
public class DatatypeFilter extends FilterPlanNode {

private static final Logger logger = LoggerFactory.getLogger(DatatypeFilter.class);

private final IRI datatype;
private final CoreDatatype.XSD xsdDatatype;
private StackTraceElement[] stackTrace;
Expand All @@ -37,17 +41,41 @@ public DatatypeFilter(PlanNode parent, IRI datatype) {
@Override
boolean checkTuple(Reference t) {
if (!(t.get().getValue().isLiteral())) {
logger.debug("Tuple rejected because it's not a literal. Tuple: {}", t);
return false;
}

Literal literal = (Literal) t.get().getValue();
if (xsdDatatype != null) {
if (literal.getCoreDatatype() == xsdDatatype) {
return XMLDatatypeUtil.isValidValue(literal.stringValue(), xsdDatatype);
boolean isValid = XMLDatatypeUtil.isValidValue(literal.stringValue(), xsdDatatype);
if (isValid) {
logger.trace(
"Tuple accepted because its literal value is valid according to the rules for the datatype in the XSD spec. Actual datatype: {}, Expected datatype: {}, Tuple: {}",
literal.getDatatype(), xsdDatatype, t);
} else {
logger.debug(
"Tuple rejected because its literal value is invalid according to the rules for the datatype in the XSD spec. Actual datatype: {}, Expected datatype: {}, Tuple: {}",
literal.getDatatype(), xsdDatatype, t);
}
return isValid;
}
logger.debug(
"Tuple rejected because literal's core datatype is not the expected datatype. Actual datatype: {}, Expected datatype: {}, Tuple: {}",
literal.getDatatype(), xsdDatatype, t);
return false;
} else {
return literal.getDatatype() == datatype || literal.getDatatype().equals(datatype);
boolean isEqual = literal.getDatatype() == datatype || literal.getDatatype().equals(datatype);
if (isEqual) {
logger.trace(
"Tuple accepted because literal's datatype is equal to the expected datatype. Actual datatype: {}, Expected datatype: {}, Tuple: {}",
literal.getDatatype(), datatype, t);
} else {
logger.debug(
"Tuple rejected because literal's datatype is not equal to the expected datatype. Actual datatype: {}, Expected datatype: {}, Tuple: {}",
literal.getDatatype(), datatype, t);
}
return isEqual;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,13 @@ boolean checkTuple(Reference t) {
t.set(map.apply(t.get(), bindingSet.next()));
} while (bindingSet.hasNext());
}
logger.trace("Tuple accepted because it matches the external query. Value: {}, Query: {}, Tuple: {}",
value, queryString, t);
return true;
}
}

logger.debug("Tuple rejected because it does not match the external query. Value: {}, Query: {}, Tuple: {}",
value, queryString, t);
return false;

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@

import org.apache.commons.text.StringEscapeUtils;
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Håvard Ottestad
*/
public class GroupByCountFilter implements PlanNode {

private static final Logger logger = LoggerFactory.getLogger(GroupByCountFilter.class);

private final Function<Long, Boolean> filter;
PlanNode parent;
private boolean printed = false;
Expand Down Expand Up @@ -74,7 +78,13 @@ private void calculateNext() {
}

if (!filter.apply(count)) {
logger.debug(
"Tuple rejected because its count does not pass the filter. Actual count: {}, Tuple: {}",
count, this.next);
this.next = null;
} else {
logger.trace("Tuple accepted because its count passes the filter. Actual count: {}, Tuple: {}",
count, this.next);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@

import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.util.Literals;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Håvard Ottestad
*/
public class LanguageInFilter extends FilterPlanNode {

private static final Logger logger = LoggerFactory.getLogger(LanguageInFilter.class);

private final List<String> languageRanges;
private final Set<String> lowerCaseLanguageIn;

Expand All @@ -37,17 +41,22 @@ public LanguageInFilter(PlanNode parent, Set<String> lowerCaseLanguageIn, List<S
@Override
boolean checkTuple(Reference t) {
if (!(t.get().getValue().isLiteral())) {
logger.debug("Tuple rejected because it's not a literal. Tuple: {}", t);
return false;
}

Optional<String> language = ((Literal) t.get().getValue()).getLanguage();
if (!language.isPresent()) {
if (language.isEmpty()) {
logger.debug("Tuple rejected because it does not have a language tag. Tuple: {}", t);
return false;
}

// early matching
boolean languageMatches = language.map(String::toLowerCase).filter(lowerCaseLanguageIn::contains).isPresent();
if (languageMatches) {
logger.trace(
"Tuple accepted because its language tag (toLowerCase()) is in the language set. Actual language: {}, Language set: {}, Tuple: {}",
language.get(), lowerCaseLanguageIn, t);
return true;
}

Expand All @@ -56,6 +65,9 @@ boolean checkTuple(Reference t) {

for (String languageRange : languageRanges) {
if (Literals.langMatches(langTag, languageRange)) {
logger.trace(
"Tuple accepted because its language tag matches the language range (BCP47). Actual language: {}, Language range: {}, Tuple: {}",
langTag, languageRange, t);
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@

import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.sail.shacl.ast.constraintcomponents.NodeKindConstraintComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Håvard Ottestad
*/
public class NodeKindFilter extends FilterPlanNode {

private static final Logger logger = LoggerFactory.getLogger(NodeKindFilter.class);

private final NodeKindConstraintComponent.NodeKind nodeKind;

public NodeKindFilter(PlanNode parent, NodeKindConstraintComponent.NodeKind nodeKind) {
Expand All @@ -32,28 +36,48 @@ public NodeKindFilter(PlanNode parent, NodeKindConstraintComponent.NodeKind node
boolean checkTuple(Reference t) {

Value value = t.get().getValue();
/*
* BlankNode(SHACL.BLANK_NODE), IRI(SHACL.IRI), Literal(SHACL.LITERAL), BlankNodeOrIRI(SHACL.BLANK_NODE_OR_IRI),
* BlankNodeOrLiteral(SHACL.BLANK_NODE_OR_LITERAL), IRIOrLiteral(SHACL.IRI_OR_LITERAL),
*/

switch (nodeKind) {
case IRI:
return value.isIRI();
if (value.isIRI()) {
logger.trace("Tuple accepted because its value is an IRI. Tuple: {}", t);
return true;
}
break;
case Literal:
return value.isLiteral();
if (value.isLiteral()) {
logger.trace("Tuple accepted because its value is a Literal. Tuple: {}", t);
return true;
}
break;
case BlankNode:
return value.isBNode();
if (value.isBNode()) {
logger.trace("Tuple accepted because its value is a BlankNode. Tuple: {}", t);
return true;
}
break;
case IRIOrLiteral:
return value.isIRI() || value.isLiteral();
if (value.isIRI() || value.isLiteral()) {
logger.trace("Tuple accepted because its value is an IRI or Literal. Tuple: {}", t);
return true;
}
break;
case BlankNodeOrIRI:
return value.isBNode() || value.isIRI();
if (value.isBNode() || value.isIRI()) {
logger.trace("Tuple accepted because its value is a BlankNode or IRI. Tuple: {}", t);
return true;
}
break;
case BlankNodeOrLiteral:
return value.isBNode() || value.isLiteral();
if (value.isBNode() || value.isLiteral()) {
logger.trace("Tuple accepted because its value is a BlankNode or Literal. Tuple: {}", t);
return true;
}
break;
}

throw new IllegalStateException("Unknown nodeKind");

logger.debug("Tuple rejected because its value does not match the expected node kind. Tuple: {}", t);
return false;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,55 +15,65 @@
import java.util.regex.Pattern;

import org.eclipse.rdf4j.model.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Håvard Ottestad
*/
public class PatternFilter extends FilterPlanNode {

private static final Logger logger = LoggerFactory.getLogger(PatternFilter.class);

private final Pattern pattern;

public PatternFilter(PlanNode parent, String pattern, String flags) {
super(parent);
if (flags != null && !flags.isEmpty()) {

int flag = 0b0;

if (flags.contains("i")) {
flag = flag | Pattern.CASE_INSENSITIVE;
logger.trace("PatternFilter constructed with case insensitive flag");
}

if (flags.contains("d")) {
flag = flag | Pattern.UNIX_LINES;
logger.trace("PatternFilter constructed with UNIX lines flag");
}

if (flags.contains("m")) {
flag = flag | Pattern.MULTILINE;
logger.trace("PatternFilter constructed with multiline flag");
}

if (flags.contains("s")) {
flag = flag | Pattern.DOTALL;
logger.trace("PatternFilter constructed with dotall flag");
}

if (flags.contains("u")) {
flag = flag | Pattern.UNICODE_CASE;
logger.trace("PatternFilter constructed with unicode case flag");
}

if (flags.contains("x")) {
flag = flag | Pattern.COMMENTS;
logger.trace("PatternFilter constructed with comments flag");
}

if (flags.contains("U")) {
flag = flag | Pattern.UNICODE_CHARACTER_CLASS;
logger.trace("PatternFilter constructed with unicode character class flag");
}

this.pattern = Pattern.compile(pattern, flag);
logger.trace("PatternFilter constructed with pattern: {} and flags: {}", pattern, flags);

} else {
this.pattern = Pattern.compile(pattern);

logger.trace("PatternFilter constructed with pattern: {} and no flags", pattern);
}

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public static PlanNode getInstance(PlanNode parent, boolean compress) {
if (parent.isGuaranteedEmpty()) {
return parent;
}

if (parent instanceof Unique && (!compress || ((Unique) parent).compress == compress)) {
return parent;
}

return new Unique(parent, compress);
}

Expand Down

0 comments on commit 516bf0a

Please sign in to comment.