Skip to content

Commit

Permalink
For beta release
Browse files Browse the repository at this point in the history
Signed-off-by: yatanokarasu <[email protected]>
  • Loading branch information
yatanokarasu committed Jan 23, 2018
1 parent 061d687 commit 98b30ab
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 83 deletions.
33 changes: 26 additions & 7 deletions src/main/java/io/sniffer4j/LogBroker.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import java.io.PrintWriter;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
Expand Down Expand Up @@ -70,13 +69,17 @@ public static LogBroker instance() {

/**
* @param aThread An instance of {@link Thread} that called this method
* @param className Name of class which called this method
* @param methodName Name of method which called this method
* @param begin An instant at the beginning of method execution
* @param end An instant at the end of method execution
*/
public void submit(final Thread aThread, final Instant begin, final Instant end) {
public void submit(final Thread aThread, final String className, final String methodName, final Instant begin, final Instant end) {
final Record aRecord = new Record();
aRecord.threadName = aThread.getName();
aRecord.threadId = aThread.getId();
aRecord.className = className;
aRecord.methodName = methodName;
aRecord.begin = begin;
aRecord.end = end;

Expand Down Expand Up @@ -147,7 +150,7 @@ public void run() {

private void startConsumerThread() {
this.consumer.execute(() -> {
try (final BufferedWriter buffer = Files.newBufferedWriter(Paths.get("d:", "sniffer4j.log"), CREATE, TRUNCATE_EXISTING);
try (final BufferedWriter buffer = Files.newBufferedWriter(Options.LOGFILE.value(), CREATE, TRUNCATE_EXISTING);
final PrintWriter writer = new PrintWriter(buffer)) {
writer.println(csvFileHeader());

Expand All @@ -172,16 +175,20 @@ private static final class Record {

private Instant end;

private String className;

private String methodName;

private long threadId;

private String threadName;


private String begin() {
return toLocalDateTime(this.begin);
}


private String end() {
return toLocalDateTime(this.end);
}
Expand All @@ -192,6 +199,16 @@ private String duration() {
}


private String className() {
return this.className;
}


private String methodName() {
return this.methodName;
}


private String threadId() {
return String.valueOf(this.threadId);
}
Expand All @@ -215,6 +232,8 @@ public String toString() {
return new StringJoiner(",")
.add(threadName())
.add(threadId())
.add(className())
.add(methodName())
.add(begin())
.add(end())
.add(duration())
Expand Down
218 changes: 192 additions & 26 deletions src/main/java/io/sniffer4j/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,61 +24,227 @@
package io.sniffer4j;


import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;


/**
* Defines options used by Sniffer4j.
*
* <p>When instanciate this class, the following arguments is mandatory:
* <dl>
* <dt><code>defaultValue</code></dt>
* <dd>Default value of the option</dd>
*
* <dt><code>converter</code></dt>
* <dd>{@link Function} to convert from String to Parameterized type</dd>
* </dl>
*
* <p>Also, you can specify the following arguments as optional:
* <dl>
* <dt><code>prehook</code></dt>
* <dd>{@link UnaryOperator} for converting new value to desired format like
* <code>"*" -> ".*"</code> in Regex</dd>
* <dt><code>composer</code></dt>
* <dd>{@link BiFunction} for composing or replacing default value and new value</dd>
* </dl>
*/
class Options<L> {

static final Options<Predicate<String>> PATTERNS = new Options<>(
Pattern.compile("^(javax?|jdk|(com\\.|)(sun|oracle))").asPredicate().negate(),
(defaultHandler, newValue) -> defaultHandler.and(Pattern.compile(newValue).asPredicate()),
s -> s.replace(";", "|")
);
static final Options<Path> LOGFILE = Options.<Path> builder()
.defaultValue(Paths.get(".", "sniffer4j.log"))
.converter(v -> {
// @formatter:off
final Path logPath = Paths.get(v);
final Path parentDir = logPath.getParent();

try {
Files.createDirectories(parentDir);
Files.createFile(logPath);
} catch (final IOException cause) {
throw new UncheckedIOException(cause);
}

return logPath;
})// @formatter:on
.build();

static final Options<Predicate<String>> PACKAGES = Options.<Predicate<String>> builder()
.defaultValue(Pattern.compile("^(javax?|jdk|(com/|)(sun|oracle)|io/sniffer4j).*").asPredicate())
.converter(v -> Pattern.compile(v).asPredicate())
.withOptional()
.prehook(v -> v.replace(";", "|").replace(".", "/").replaceAll("*", Pattern.quote("*")))
.composer((o, n) -> o.or(n.negate()))
.build();

@SuppressWarnings("boxing")
static final Options<Integer> INTERVAL = new IntValueOptions(Integer.MIN_VALUE);

@SuppressWarnings("boxing")
static final Options<Integer> THRESHOLD = new IntValueOptions(Integer.MIN_VALUE);

private final L defaultHandler;
static final Options<Void> NULL = new NullOptions();

private final BiFunction<L, String, L> updateHandler;

private Function<String, String> hook;
private final BiFunction<L, L, L> composer;

private L handler;
private final Function<String, L> converter;

private final Function<String, String> prehook;

private Options(final L defaultHandler, final BiFunction<L, String, L> updateHandler) {
this(defaultHandler, updateHandler, Function.identity());
private L value;


private Options(final L defaultValue, final Function<String, L> converter) {
this(defaultValue, converter, UnaryOperator.identity(), (o, n) -> n);
}


private Options(final L defaultHandler, final BiFunction<L, String, L> updateHandler, final Function<String, String> hook) {
this.defaultHandler = defaultHandler;
this.updateHandler = updateHandler;
this.hook = hook;


private Options(final L defaultValue, final Function<String, L> converter, final UnaryOperator<String> prehook, final BiFunction<L, L, L> composer) {
this.value = defaultValue;
this.converter = converter;
this.prehook = prehook;
this.composer = composer;
}


static Options<?> valueOf(final String name) {
private static <L> MandatoryValueBuilder<L> builder() {
return new MandatoryValueBuilder<>();
}


static Options<?> of(final String name) {
switch (name.toUpperCase()) {
case "PATTERNS":
return PATTERNS;
// @formatter:off
case "PACKAGES": return PACKAGES;
case "THRESHOLD": return THRESHOLD;
case "LOGFILE": return LOGFILE;
// @formatter:on
default:
throw new IllegalArgumentException("No constant " + name + ".");
System.err.println("No option: " + name + ".");
return NULL;
}
}


void value(final String newValue) {
try {
L converted = this.converter.apply(this.prehook.apply(newValue));
this.value = this.composer.apply(this.value, converted);
} catch (final Throwable cause) {
throw new IllegalArgumentException(cause);
}
}


L value() {
return this.value;
}


private static final class IntValueOptions extends Options<Integer> {

private IntValueOptions(final Integer defaultValue) {
super(defaultValue, Integer::valueOf);
}

}


private static final class MandatoryValueBuilder<L> {

private Function<String, L> converter;

private L defaultValue;


private Options<L> build() {
validate();

return new Options<>(this.defaultValue, this.converter);
}


private MandatoryValueBuilder<L> converter(final Function<String, L> converter) {
this.converter = converter;
return this;
}


private MandatoryValueBuilder<L> defaultValue(final L defaultValue) {
this.defaultValue = defaultValue;
return this;
}


private void validate() {
if (Objects.isNull(this.defaultValue) || Objects.isNull(this.converter)) {
throw new IllegalStateException();
}
}


private OptionalValueBuilder<L> withOptional() {
validate();

return new OptionalValueBuilder<>(this.defaultValue, this.converter);
}

}


L handler() {
return this.handler;
private static final class NullOptions extends Options<Void> {

private NullOptions() {
super(null, null);
}

}


void update(final String value) {
this.handler = this.updateHandler.apply(this.defaultHandler, this.hook.apply(value));
private static final class OptionalValueBuilder<L> {

private final L defaultValue;

private final Function<String, L> converter;

private UnaryOperator<String> prehook;

private BiFunction<L, L, L> composer;


private OptionalValueBuilder(final L defaultValue, final Function<String, L> converter) {
this.defaultValue = defaultValue;
this.converter = converter;
this.prehook = UnaryOperator.identity();
this.composer = (o, n) -> n;
}


private Options<L> build() {
return new Options<>(this.defaultValue, this.converter, this.prehook, this.composer);
}


private OptionalValueBuilder<L> composer(final BiFunction<L, L, L> composer) {
this.composer = composer;
return this;
}


private OptionalValueBuilder<L> prehook(final UnaryOperator<String> prehook) {
this.prehook = prehook;
return this;
}

}

}
Loading

0 comments on commit 98b30ab

Please sign in to comment.