/* * Copyright (c) 2002-2017 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.neo4j.driver.v1; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; import org.neo4j.driver.internal.Event; import org.neo4j.driver.internal.EventHandler; import static java.util.Objects.requireNonNull; public class EventLogger implements Logger { public static Logging provider( EventHandler events, Level level ) { return provider( sink( requireNonNull( events, "events" ) ), level ); } public static Logging provider( final Sink events, final Level level ) { requireNonNull( events, "events" ); requireNonNull( level, "level" ); return new Logging() { @Override public Logger getLog( String name ) { return new EventLogger( events, name, level ); } }; } public interface Sink { void log( String name, Level level, Throwable cause, String message, Object... params ); } private final boolean debug, trace; private final Sink events; private final String name; public EventLogger( EventHandler events, String name, Level level ) { this( sink( requireNonNull( events, "events" ) ), name, level ); } public EventLogger( Sink events, String name, Level level ) { this.events = requireNonNull( events, "events" ); this.name = name; level = requireNonNull( level, "level" ); this.debug = Level.DEBUG.compareTo( level ) <= 0; this.trace = Level.TRACE.compareTo( level ) <= 0; } private static Sink sink( final EventHandler events ) { return new Sink() { @Override public void log( String name, Level level, Throwable cause, String message, Object... params ) { events.add( new Entry( Thread.currentThread(), name, level, cause, message, params ) ); } }; } public enum Level { ERROR, WARN, INFO, DEBUG, TRACE } @Override public void error( String message, Throwable cause ) { events.log( name, Level.ERROR, cause, message ); } @Override public void info( String message, Object... params ) { events.log( name, Level.INFO, null, message, params ); } @Override public void warn( String message, Object... params ) { events.log( name, Level.WARN, null, message, params ); } @Override public void debug( String message, Object... params ) { events.log( name, Level.DEBUG, null, message, params ); } @Override public void trace( String message, Object... params ) { events.log( name, Level.TRACE, null, message, params ); } @Override public boolean isTraceEnabled() { return trace; } @Override public boolean isDebugEnabled() { return debug; } public static final class Entry extends Event<Sink> { private final Thread thread; private final String name; private final Level level; private final Throwable cause; private final String message; private final Object[] params; private Entry( Thread thread, String name, Level level, Throwable cause, String message, Object... params ) { this.thread = thread; this.name = name; this.level = requireNonNull( level, "level" ); this.cause = cause; this.message = message; this.params = params; } @Override public void dispatch( Sink sink ) { sink.log( name, level, cause, message, params ); } private String formatted() { return params == null ? message : String.format( message, params ); } public static Matcher<Entry> logEntry( final Matcher<Thread> thread, final Matcher<String> name, final Matcher<Level> level, final Matcher<Throwable> cause, final Matcher<String> message, final Matcher<Object[]> params ) { return new TypeSafeMatcher<Entry>() { @Override protected boolean matchesSafely( Entry entry ) { return level.matches( entry.level ) && thread.matches( entry.thread ) && name.matches( entry.name ) && cause.matches( entry.cause ) && message.matches( entry.message ) && params.matches( entry.params ); } @Override public void describeTo( Description description ) { description.appendText( "Log entry where level " ) .appendDescriptionOf( level ) .appendText( " name <" ) .appendDescriptionOf( name ) .appendText( "> cause <" ) .appendDescriptionOf( cause ) .appendText( "> message <" ) .appendDescriptionOf( message ) .appendText( "> and parameters <" ) .appendDescriptionOf( params ) .appendText( ">" ); } }; } public static Matcher<Entry> message( final Matcher<Level> level, final Matcher<String> message ) { return new TypeSafeMatcher<Entry>() { @Override protected boolean matchesSafely( Entry entry ) { return level.matches( entry.level ) && message.matches( entry.formatted() ); } @Override public void describeTo( Description description ) { description.appendText( "Log entry where level " ).appendDescriptionOf( level ) .appendText( " and formatted message " ).appendDescriptionOf( message ); } }; } } }