Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.github.tonivade.purefun.effect.util;

import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import com.github.tonivade.purefun.core.Producer;
import com.github.tonivade.purefun.core.Unit;
import com.github.tonivade.purefun.effect.RIO;

public interface PureLog {

<R extends PureLog> PureLog.Service<R> logger(StackFrame frame);

static <R extends PureLog> RIO<R, Unit> debug(Producer<String> message) {
var frame = getFrame();
return RIO.accessM(env -> env.<R>logger(frame).debug(message));
}

static <R extends PureLog> RIO<R, Unit> info(Producer<String> message) {
var frame = getFrame();
return RIO.accessM(env -> env.<R>logger(frame).info(message));
}

static <R extends PureLog> RIO<R, Unit> warn(Producer<String> message) {
var frame = getFrame();
return RIO.accessM(env -> env.<R>logger(frame).warn(message));
}

static <R extends PureLog> RIO<R,Unit> error(Producer<String> message) {
var frame = getFrame();
return RIO.accessM(env -> env.<R>logger(frame).error(message));
}

interface Service<R extends PureLog> {

default RIO<R, Unit> debug(Producer<String> message) {
return log(Level.FINE, message);
}

default RIO<R, Unit> info(Producer<String> message) {
return log(Level.INFO, message);
}

default RIO<R, Unit> warn(Producer<String> message) {
return log(Level.WARNING, message);
}

default RIO<R, Unit> error(Producer<String> message) {
return log(Level.SEVERE, message);
}

RIO<R, Unit> log(Level level, Producer<String> message);
}

static PureLog javaUtilLogging() {
return new PureLog() {
@Override
public <R extends PureLog> Service<R> logger(StackFrame frame) {
return (level, message) -> {
var logger = Logger.getLogger(frame.getClassName());
return RIO.exec(() -> logger.logp(level, frame.getClassName(), frame.getMethodName(), message.get()));
};
}
};
}

static PureLog test(final Queue<LogRecord> traces) {
return new PureLog() {
@Override
public <R extends PureLog> Service<R> logger(StackFrame frame) {
return (level, message) -> RIO.exec(() -> {
var log = new LogRecord(level, message.get());
log.setSourceClassName(frame.getClassName());
log.setSourceMethodName(frame.getMethodName());
traces.add(log);
});
}
};
}

private static StackFrame getFrame() {
var walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE);
return walker.walk(frames -> frames.skip(2).findFirst().orElseThrow());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static com.github.tonivade.purefun.effect.RIO.sleep;
import static com.github.tonivade.purefun.effect.RIO.task;
import static com.github.tonivade.purefun.effect.RIOOf.toRIO;
import static com.github.tonivade.purefun.effect.util.PureLog.info;
import static java.util.concurrent.ThreadLocalRandom.current;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
Expand All @@ -36,6 +37,7 @@
import com.github.tonivade.purefun.core.Producer;
import com.github.tonivade.purefun.core.Unit;
import com.github.tonivade.purefun.data.Sequence;
import com.github.tonivade.purefun.effect.util.PureLog;
import com.github.tonivade.purefun.instances.RIOInstances;
import com.github.tonivade.purefun.type.Either;
import com.github.tonivade.purefun.type.Try;
Expand Down Expand Up @@ -171,22 +173,22 @@ public void traverse() {

@Test
void raceA() {
RIO<Void, Either<Integer, String>> race = race(
RIO.<Void>sleep(Duration.ofMillis(10)).map(x -> 10),
RIO.<Void>sleep(Duration.ofMillis(100)).map(x -> "b"));
RIO<PureLog, Either<Integer, String>> race = race(
RIO.<PureLog>sleep(Duration.ofMillis(10)).andThen(info(() -> "done A")).map(x -> 10),
RIO.<PureLog>sleep(Duration.ofMillis(100)).andThen(info(() -> "done B")).map(x -> "b"));

Try<Either<Integer, String>> orElseThrow = race.safeRunSync(null);
Try<Either<Integer, String>> orElseThrow = race.safeRunSync(PureLog.javaUtilLogging());

assertEquals(Try.success(Either.left(10)), orElseThrow);
}

@Test
void raceB() {
RIO<Void, Either<Integer, String>> race = race(
RIO.<Void>sleep(Duration.ofMillis(100)).map(x -> 10),
RIO.<Void>sleep(Duration.ofMillis(10)).map(x -> "b"));
RIO<PureLog, Either<Integer, String>> race = race(
RIO.<PureLog>sleep(Duration.ofMillis(100)).andThen(info(() -> "done A")).map(x -> 10),
RIO.<PureLog>sleep(Duration.ofMillis(10)).andThen(info(() -> "done B")).map(x -> "b"));

Try<Either<Integer, String>> orElseThrow = race.safeRunSync(null);
Try<Either<Integer, String>> orElseThrow = race.safeRunSync(PureLog.javaUtilLogging());

assertEquals(Try.success(Either.right("b")), orElseThrow);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.github.tonivade.purefun.effect.util;

import static org.junit.jupiter.api.Assertions.*;

import java.util.LinkedList;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.LogRecord;

import org.junit.jupiter.api.Test;

class PureLogTest {

@Test
void test() {
Queue<LogRecord> traces = new LinkedList<>();

PureLog.info(() -> "this is a test").safeRunSync(PureLog.test(traces));

LogRecord logRecord = traces.poll();
assertEquals("this is a test", logRecord.getMessage());
assertEquals(Level.INFO, logRecord.getLevel());
assertEquals(PureLogTest.class.getName(), logRecord.getSourceClassName());
assertEquals("test", logRecord.getSourceMethodName());
}
}