Browse Source

Improved logging support

We now use a logger factory, which means loggers can be created
per class.

This allows use of 'wrapped' Apache log4j2 loggers with the added
benefit of more accurate class/line-number reporting.
master
catbref 4 years ago
parent
commit
466ffa4d4d
  1. 11
      Java/src/main/java/org/ciyam/at/AtLogger.java
  2. 7
      Java/src/main/java/org/ciyam/at/AtLoggerFactory.java
  3. 11
      Java/src/main/java/org/ciyam/at/LoggerInterface.java
  4. 26
      Java/src/main/java/org/ciyam/at/MachineState.java
  5. 2
      Java/src/test/java/org/ciyam/at/MiscTests.java
  6. 10
      Java/src/test/java/org/ciyam/at/SerializationTests.java
  7. 10
      Java/src/test/java/org/ciyam/at/test/ExecutableTest.java
  8. 5
      Java/src/test/java/org/ciyam/at/test/TestLogger.java
  9. 13
      Java/src/test/java/org/ciyam/at/test/TestLoggerFactory.java

11
Java/src/main/java/org/ciyam/at/AtLogger.java

@ -0,0 +1,11 @@
package org.ciyam.at;
public interface AtLogger {
void error(final String message);
void debug(final String message);
void echo(final String message);
}

7
Java/src/main/java/org/ciyam/at/AtLoggerFactory.java

@ -0,0 +1,7 @@
package org.ciyam.at;
public interface AtLoggerFactory {
AtLogger create(final Class<?> loggerName);
}

11
Java/src/main/java/org/ciyam/at/LoggerInterface.java

@ -1,11 +0,0 @@
package org.ciyam.at;
public interface LoggerInterface {
public void error(String message);
public void debug(String message);
public void echo(String message);
}

26
Java/src/main/java/org/ciyam/at/MachineState.java

@ -126,7 +126,8 @@ public class MachineState {
private boolean isFirstOpCodeAfterSleeping;
private API api;
private LoggerInterface logger;
private AtLoggerFactory loggerFactory;
private AtLogger logger;
// NOTE: These are package-scope to allow easy access/operations in Opcode/FunctionCode.
/* package */ ByteBuffer codeByteBuffer;
@ -137,7 +138,7 @@ public class MachineState {
// Constructors
/** For internal use when recreating a machine state */
private MachineState(API api, LoggerInterface logger, byte[] headerBytes) {
private MachineState(byte[] headerBytes, API api, AtLoggerFactory loggerFactory) {
if (headerBytes.length != HEADER_LENGTH)
throw new IllegalArgumentException("headerBytes length " + headerBytes.length + " incorrect, expected " + HEADER_LENGTH);
@ -190,12 +191,13 @@ public class MachineState {
this.currentBalance = 0;
this.previousBalance = 0;
this.steps = 0;
this.logger = logger;
this.loggerFactory = loggerFactory;
this.logger = loggerFactory.create(MachineState.class);
}
/** For creating a new machine state */
public MachineState(API api, byte[] creationBytes) {
this(api, null, Arrays.copyOfRange(creationBytes, 0, HEADER_LENGTH));
public MachineState(API api, AtLoggerFactory loggerFactory, byte[] creationBytes) {
this(Arrays.copyOfRange(creationBytes, 0, HEADER_LENGTH), api, loggerFactory);
int expectedLength = HEADER_LENGTH + this.numCodePages * this.constants.CODE_PAGE_SIZE + this.numDataPages * this.constants.DATA_PAGE_SIZE;
if (creationBytes.length != expectedLength)
@ -210,8 +212,8 @@ public class MachineState {
}
/** For creating a new machine state - used in tests */
public MachineState(API api, LoggerInterface logger, byte[] headerBytes, byte[] codeBytes, byte[] dataBytes) {
this(api, logger, headerBytes);
public MachineState(API api, AtLoggerFactory loggerFactory, byte[] headerBytes, byte[] codeBytes, byte[] dataBytes) {
this(headerBytes, api, loggerFactory);
if (codeBytes.length > this.numCodePages * this.constants.CODE_PAGE_SIZE)
throw new IllegalArgumentException("Number of code pages too small to hold code bytes");
@ -342,7 +344,11 @@ public class MachineState {
return this.api;
}
public LoggerInterface getLogger() {
public AtLoggerFactory getLoggerFactory() {
return this.loggerFactory;
}
/* package */ AtLogger getLogger() {
return this.logger;
}
@ -516,13 +522,13 @@ public class MachineState {
}
/** For restoring a previously serialized machine state */
public static MachineState fromBytes(API api, LoggerInterface logger, byte[] bytes, byte[] codeBytes) {
public static MachineState fromBytes(API api, AtLoggerFactory loggerFactory, byte[] bytes, byte[] codeBytes) {
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
byte[] headerBytes = new byte[HEADER_LENGTH];
byteBuffer.get(headerBytes);
MachineState state = new MachineState(api, logger, headerBytes);
MachineState state = new MachineState(headerBytes, api, loggerFactory);
if (codeBytes.length != state.codeByteBuffer.capacity())
throw new IllegalStateException("Passed codeBytes does not match length in header");

2
Java/src/test/java/org/ciyam/at/MiscTests.java

@ -62,7 +62,7 @@ public class MiscTests extends ExecutableTest {
byte[] codeBytes = codeByteBuffer.array();
byte[] dataBytes = new byte[0];
state = new MachineState(api, logger, headerBytes, codeBytes, dataBytes);
state = new MachineState(api, loggerFactory, headerBytes, codeBytes, dataBytes);
assertTrue(state.isFrozen());
assertEquals((Long) (minActivationAmount - 1L), state.getFrozenBalance());

10
Java/src/test/java/org/ciyam/at/SerializationTests.java

@ -102,12 +102,12 @@ public class SerializationTests extends ExecutableTest {
byte[] codeBytes = codeByteBuffer.array();
byte[] dataBytes = dataByteBuffer.array();
state = new MachineState(api, logger, headerBytes, codeBytes, dataBytes);
state = new MachineState(api, loggerFactory, headerBytes, codeBytes, dataBytes);
packedState = state.toBytes();
byte[] creationBytes = MachineState.toCreationBytes(TestUtils.VERSION, codeBytes, dataBytes, TestUtils.NUM_CALL_STACK_PAGES, TestUtils.NUM_USER_STACK_PAGES, TestUtils.MIN_ACTIVATION_AMOUNT);
MachineState restoredState = new MachineState(api, creationBytes);
MachineState restoredState = new MachineState(api, loggerFactory, creationBytes);
byte[] packedRestoredSate = restoredState.toBytes();
assertTrue(Arrays.equals(packedState, packedRestoredSate));
@ -118,14 +118,14 @@ public class SerializationTests extends ExecutableTest {
byte[] codeBytes = codeByteBuffer.array();
byte[] dataBytes = new byte[0];
state = new MachineState(api, logger, headerBytes, codeBytes, dataBytes);
state = new MachineState(api, loggerFactory, headerBytes, codeBytes, dataBytes);
return executeAndCheck(state);
}
private byte[] continueSimulation(byte[] savedState) {
byte[] codeBytes = codeByteBuffer.array();
state = MachineState.fromBytes(api, logger, savedState, codeBytes);
state = MachineState.fromBytes(api, loggerFactory, savedState, codeBytes);
// Pretend we're on next block
api.bumpCurrentBlockHeight();
@ -141,7 +141,7 @@ public class SerializationTests extends ExecutableTest {
byte[] codeBytes = state.getCodeBytes();
// Rebuild new MachineState using fetched state & bytes
MachineState restoredState = MachineState.fromBytes(api, logger, stateBytes, codeBytes);
MachineState restoredState = MachineState.fromBytes(api, loggerFactory, stateBytes, codeBytes);
// Extract rebuilt state and code bytes
byte[] restoredStateBytes = restoredState.toBytes();
byte[] restoredCodeBytes = state.getCodeBytes();

10
Java/src/test/java/org/ciyam/at/test/ExecutableTest.java

@ -14,7 +14,7 @@ public abstract class ExecutableTest {
private static final int DATA_OFFSET = MachineState.HEADER_LENGTH; // code bytes are not present
private static final int CALL_STACK_OFFSET = DATA_OFFSET + TestUtils.NUM_DATA_PAGES * MachineState.VALUE_SIZE;
public TestLogger logger;
public TestLoggerFactory loggerFactory;
public TestAPI api;
public MachineState state;
public ByteBuffer codeByteBuffer;
@ -32,7 +32,7 @@ public abstract class ExecutableTest {
@Before
public void beforeTest() {
logger = new TestLogger();
loggerFactory = new TestLoggerFactory();
api = new TestAPI();
codeByteBuffer = ByteBuffer.allocate(TestUtils.NUM_CODE_PAGES * MachineState.OPCODE_SIZE);
dataByteBuffer = ByteBuffer.allocate(TestUtils.NUM_DATA_PAGES * MachineState.VALUE_SIZE);
@ -47,7 +47,7 @@ public abstract class ExecutableTest {
codeByteBuffer = null;
dataByteBuffer = null;
api = null;
logger = null;
loggerFactory = null;
}
protected void execute(boolean onceOnly) {
@ -58,12 +58,12 @@ public abstract class ExecutableTest {
if (packedState == null) {
// First time
System.out.println("First execution - deploying...");
state = new MachineState(api, logger, headerBytes, codeBytes, dataBytes);
state = new MachineState(api, loggerFactory, headerBytes, codeBytes, dataBytes);
packedState = state.toBytes();
}
do {
state = MachineState.fromBytes(api, logger, packedState, codeBytes);
state = MachineState.fromBytes(api, loggerFactory, packedState, codeBytes);
System.out.println("Starting execution round!");
System.out.println("Current block height: " + api.getCurrentBlockHeight());

5
Java/src/test/java/org/ciyam/at/test/TestLogger.java

@ -1,8 +1,9 @@
package org.ciyam.at.test;
import org.ciyam.at.LoggerInterface;
import org.ciyam.at.AtLogger;
public class TestLogger implements AtLogger {
public class TestLogger implements LoggerInterface {
@Override
public void error(String message) {
System.err.println("ERROR: " + message);

13
Java/src/test/java/org/ciyam/at/test/TestLoggerFactory.java

@ -0,0 +1,13 @@
package org.ciyam.at.test;
import org.ciyam.at.AtLogger;
import org.ciyam.at.AtLoggerFactory;
public class TestLoggerFactory implements AtLoggerFactory {
@Override
public AtLogger create(Class<?> loggerName) {
return new TestLogger();
}
}
Loading…
Cancel
Save