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

Method logging aspects #313

Open
wants to merge 43 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
3780a5e
Test implementation annotations for methods
dschiese Aug 27, 2024
fc2795f
Set up aspects
dschiese Aug 28, 2024
09151e7
Added logging storage
dschiese Aug 28, 2024
2f04426
Added log storage
dschiese Aug 28, 2024
f9b3093
Added class
dschiese Aug 28, 2024
8b61033
Added Logging for components
dschiese Aug 30, 2024
a8eea28
[Done]: QTSC problem for all cases
dschiese Sep 2, 2024
85498c8
Added component name to stored data
dschiese Sep 2, 2024
915667a
Added method logging for pipeline, starting with QA process begin
dschiese Sep 2, 2024
53cd7dc
WIP; Missing pipeline for now
dschiese Sep 3, 2024
dcb86b4
WIP
dschiese Oct 15, 2024
d591f84
WIP
dschiese Oct 16, 2024
4a63154
WIP
dschiese Oct 16, 2024
23213e2
WIP
dschiese Oct 16, 2024
04d65a2
WIP
dschiese Oct 16, 2024
51a6857
Cleaned LoggingAspect
dschiese Oct 17, 2024
6f815ef
Tests: WIP
dschiese Oct 18, 2024
c3c900b
WIP
dschiese Oct 19, 2024
2b54f4e
WIP
dschiese Oct 19, 2024
079c931
WIP; working query isnertion
dschiese Nov 6, 2024
7dac034
Edited query for inserting data, added data formatting for java Objects
dschiese Nov 6, 2024
33c17af
WIP: Aspect for pipeline
dschiese Nov 6, 2024
02cbaf5
[Added]: Handling if query data contains newlines, [Refactor]: Separa…
dschiese Nov 12, 2024
aed9fd5
Revoke changes
dschiese Nov 12, 2024
063eae1
Revoked unnecessary changes
dschiese Nov 12, 2024
a06f77e
Bugfixes
dschiese Nov 12, 2024
69edf36
WIP
dschiese Dec 30, 2024
5185012
Adjusted pom files
dschiese Dec 30, 2024
c4660eb
Merge branch 'aspectAndLogging' of github.com:WDAqua/Qanary into aspe…
dschiese Dec 30, 2024
7a21d65
Empty stack item now again 'init'. Otherwise it caused a empty resour…
dschiese Dec 30, 2024
1f14e51
Refactored formatting, (re)added qtsc.udpdate for methods
dschiese Jan 1, 2025
493ab75
Revert changes for qanary component template
dschiese Jan 1, 2025
d4d6fbe
Removed aop.xml definitions
dschiese Jan 1, 2025
79d8ee5
Revert "Removed aop.xml definitions"
dschiese Jan 1, 2025
45c1691
Revert "Revert changes for qanary component template"
dschiese Jan 1, 2025
7a498ba
Removed aop.xml definitions
dschiese Jan 1, 2025
b7e7e33
WIP: Tests, EDIT: component aspect
dschiese Jan 1, 2025
09fb1e3
Delete qanary_commons/src/test/java/qa/commons/LoggingAspectComponent…
dschiese Jan 1, 2025
01bb3bf
Solved applicationName problem and removed abstract class LoggingAspe…
dschiese Jan 2, 2025
6765ca7
Added Graph and TS endpoint recognition
dschiese Jan 2, 2025
74e7d87
Added aspect for pipeline
dschiese Jan 2, 2025
f3401f7
Fixing code
dschiese Jan 2, 2025
a6d976d
Added exception handling for testing purposes
dschiese Jan 2, 2025
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
47 changes: 45 additions & 2 deletions qanary_commons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>eu.wdaqua.qanary</groupId>
<artifactId>qa.commons</artifactId>
<version>3.18.1</version>
<version>3.19.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
Expand Down Expand Up @@ -262,7 +262,16 @@
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
</dependencies>
<repositories>
<repository>
<id>Stardog</id>
Expand Down Expand Up @@ -424,6 +433,40 @@
</execution>
</executions>
</plugin>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>16</source>
<target>16</target>
</configuration>
</plugin>
-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.14.0</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>UTF-8 </encoding>
</configuration>
<executions>
<execution>
<goals>
<!-- use this goal to weave all your main classes -->
<goal>compile</goal>
<!-- use this goal to weave all your test classes -->
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
package eu.wdaqua.qanary.explainability.annotations;

import eu.wdaqua.qanary.commons.QanaryMessage;
import eu.wdaqua.qanary.commons.QanaryUtils;
import eu.wdaqua.qanary.commons.triplestoreconnectors.QanaryTripleStoreConnector;
import eu.wdaqua.qanary.commons.triplestoreconnectors.QanaryTripleStoreConnectorQanaryInternal;
import eu.wdaqua.qanary.exceptions.SparqlQueryFailed;
import org.apache.jena.rdf.model.ResourceFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;

/**
* This class' purpose is to log all method executions within the process()-method.
* It is done by starting the logging process before the process()-method is called and ending it when the method returns.
*/

@Aspect
public class LoggingAspectComponent {

private URI processGraph;
private QanaryTripleStoreConnector qanaryTripleStoreConnector;

public QanaryTripleStoreConnector getQanaryTripleStoreConnector() {
return qanaryTripleStoreConnector;
}

public void setQanaryTripleStoreConnector(QanaryTripleStoreConnector qanaryTripleStoreConnector) {
this.qanaryTripleStoreConnector = qanaryTripleStoreConnector;
}

public URI getProcessGraph() {
return processGraph;
}

public void setProcessGraph(URI processGraph) {
this.processGraph = processGraph;
}

public QanaryTripleStoreConnectorQanaryInternal createTriplestoreConnectorFromJoinPoint(JoinPoint joinPoint,
String applicationName) throws URISyntaxException {
QanaryMessage qanaryMessage = (QanaryMessage) joinPoint.getArgs()[2];
return new QanaryTripleStoreConnectorQanaryInternal(qanaryMessage.getEndpoint(), applicationName);
}

public URI createGraphFromJoinPoint(JoinPoint joinPoint) {
QanaryMessage qanaryMessage = (QanaryMessage) joinPoint.getArgs()[2];
return qanaryMessage.getInGraph();
}

private Logger logger = LoggerFactory.getLogger(LoggingAspectComponent.class);
private Map<String, MethodObject> methodList = new HashMap<>();
private final String LOGGING_QUERY = "/queries/logging/insert_method_data.rq";
private Stack<String> callStack = new Stack<String>();
private String applicationName;
public final String MAP_IS_NULL_ERROR = "Passed map is null; No method logged";
public final String EMPTY_STACK_ITEM = "init";

public Stack<String> getCallStack() {
return callStack;
}

public void setCallStack(Stack<String> callStack) {
this.callStack = callStack;
}

public Map<String, MethodObject> getMethodList() {
return methodList;
}

public void setMethodList(Map<String, MethodObject> methodList) {
this.methodList = methodList;
}

/**
* Logs method by using the defined logging query.
*
* @param methodUuid UUID of the method to be logged
* @param method Oject that contains all details needed to get logged
* @throws IOException During read-process of logging-query
* @throws SparqlQueryFailed During update-process with the final query
*/
public void logMethodData(String methodUuid, MethodObject method)
throws IOException, SparqlQueryFailed, NullPointerException {
String query = QanaryTripleStoreConnector.readFileFromResources(LOGGING_QUERY);
query = query.replace("?graph", "<" + this.getProcessGraph().toASCIIString() + ">");
query = query.replace("?annotatedBy", "<urn:qanary:" + this.applicationName + ">");
query = query.replace("?a", "<" + methodUuid + ">");
query = query.replace("?caller", "<" + method.getCaller() + ">");
query = query.replace("?method", "'" + method.getMethod() + "'");
query = query.replace("?output", generateOutputDataRepresentation(method.getOutput()));
query = query.replace("?input", generateInputDataRepresentation(method.getInput()));
logger.info("Method-log query: {}", query);
this.qanaryTripleStoreConnector.update(query);
}

/**
* Transforms object list to SPARQL-conform representation to store data
*
* @param inputData
* @return
*/
public String generateInputDataRepresentation(Object[] inputData) {
String representation = "(";
if (inputData.length == 0 || inputData == null)
return "()";
for (int i = 0; i < inputData.length; i++) {
Object var = inputData[i];
String varRepresentation = "[ " + "rdf:type \"" + var.getClass() + "\" ;" + "rdf:value \""
+ ResourceFactory.createPlainLiteral(var.toString().replace("\n", " ").replace("\\", "")) + "\" ]";
representation += varRepresentation;
}
;
representation += ")";
return representation;
}

/**
* Creates SPARQL-conform representation for the output data
*
* @param outputData
* @return
*/
public String generateOutputDataRepresentation(Object outputData) {
if (outputData.equals(null))
return "[]";
return "[ rdf:type \"" +
ResourceFactory.createPlainLiteral(outputData.getClass().toString()) +
"\" ; rdf:value \""
+ ResourceFactory.createPlainLiteral(outputData.toString().replace("\n", " ").replace("\\", "'")) +
"\"]";
}

public void logMethods(Map<String, MethodObject> methodMap) throws RuntimeException {
// k = UUID of the actual method; v = Method details
try {
methodMap.forEach((k, v) -> {
try {
this.logMethodData(k, v);
} catch (IOException | SparqlQueryFailed | NullPointerException e) {
logger.error("Method with uuid {} was not logged due to an exception with the error message: {}", k,
e.getMessage());
}
});
} catch (NullPointerException e) {
logger.error(MAP_IS_NULL_ERROR);
}
}

// Separated due to overlapping pointcuts and thus condition race
@Pointcut("!execution(* process(eu.wdaqua.qanary.commons.QanaryMessage)) && " +
"(execution(* eu.wdaqua.qanary.component..*(..)) || " +
"execution(* eu.wdaqua.qanary.QanaryPipelineComponent..*(..)))")
public void storeMethodExecutionInComponent() {
};

@Pointcut("execution(* process(eu.wdaqua.qanary.commons.QanaryMessage))")
public void processExecution() {
};

/**
* Sets the graph from the executed process context (i.e. the
* process(QanaryMessage message) method)
*
* @param joinPoint JoinPoint
* @throws URISyntaxException Get the endpoint from the QanaryMessage
*/
@Before(value = "processExecution()")
public void setGraphFromProcessExecution(JoinPoint joinPoint) throws URISyntaxException {
resetConfiguration();
QanaryMessage qanaryMessage = (QanaryMessage) joinPoint.getArgs()[0];
this.setProcessGraph(qanaryMessage.getInGraph());
if (this.getQanaryTripleStoreConnector() == null) {
QanaryUtils qanaryUtils = new QanaryUtils(qanaryMessage,
new QanaryTripleStoreConnectorQanaryInternal(qanaryMessage.getEndpoint(), this.applicationName));
this.setQanaryTripleStoreConnector(qanaryUtils.getQanaryTripleStoreConnector());
}
implementationStoreMethodExecutionInComponentBefore(joinPoint);
}

/**
* Sets the returned object for each stored method
*
* @param joinPoint JoinPoint
* @param result Returned object
*/
@AfterReturning(value = "storeMethodExecutionInComponent()", returning = "result")
public void implementationStoreMethodExecutionInComponentAfter(JoinPoint joinPoint, Object result) {
String currentMethodUuid = (String) this.callStack.peek();
MethodObject method = this.methodList.get(currentMethodUuid);
method.setOutput(result);
this.methodList.replace(currentMethodUuid, method);
this.callStack.pop();
if (this.callStack.isEmpty()) {
logMethods(this.methodList);
this.setProcessGraph(null); // Process ended
this.methodList.clear(); // Clear stored methods
}
}

/**
* Creates a UUID for the designated method and puts it on the execution-stack.
*
* @param joinPoint JoinPoint
*/
@Before(value = "storeMethodExecutionInComponent()")
public void implementationStoreMethodExecutionInComponentBefore(JoinPoint joinPoint) {
// Get caller and self-push to stack
String caller = checkAndGetFromStack();
String uuid = UUID.randomUUID().toString();
this.callStack.push(uuid);

// Get required data
String method = joinPoint.getSignature().getName();
Object[] input = joinPoint.getArgs();

this.methodList.put(
uuid,
new MethodObject(caller, method, input, this.applicationName));
}

/**
* Helper function to get the caller method's uuid. If the stack is empty at the
* beginning, it returns "init"
*
* @return UUID for the latest stack item; "" if stack is empty (first method
* call)
*/
public String checkAndGetFromStack() {
try {
return (String) this.callStack.peek();
} catch (EmptyStackException e) {
return EMPTY_STACK_ITEM;
}
}

public void resetConfiguration() {
this.callStack.clear();
this.methodList.clear();
}

// APPLICATION NAME RELATED

@Pointcut("execution(* getApplicationName())")
public void applicationNamePointcut() {
}

@AfterReturning(value = "applicationNamePointcut()", returning = "result")
public void getApplicationNameAfterReturning(JoinPoint joinPoint, Object result) {
this.applicationName = (String) result;
logger.info("Application name set to: {}", this.applicationName);
}

}
Loading
Loading