Skip to content
This repository has been archived by the owner on Mar 16, 2021. It is now read-only.

Commit

Permalink
Merge pull request #85 from StefMa/feature/add_logging_interceptor
Browse files Browse the repository at this point in the history
Feature/add logging interceptor
  • Loading branch information
passsy authored Apr 25, 2017
2 parents 57fc2af + 5db9073 commit fb7d993
Show file tree
Hide file tree
Showing 10 changed files with 776 additions and 1 deletion.
1 change: 1 addition & 0 deletions logginginterceptor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
55 changes: 55 additions & 0 deletions logginginterceptor/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.novoda:bintray-release:$bintrayVersion"
}
}

apply plugin: 'com.android.library'
apply plugin: 'bintray-release'
apply plugin: 'jacoco-android'

android {
compileSdkVersion COMPILE_SDK_VERSION
buildToolsVersion BUILD_TOOLS_VERSION

defaultConfig {
minSdkVersion MIN_SDK_VERSION
targetSdkVersion TARGET_SDK_VERSION
versionCode VERSION_CODE
versionName VERSION_NAME
}
buildTypes {
release {
minifyEnabled false
}
debug {
// output coverage with ./gradlew clean build createDebugCoverageReport
testCoverageEnabled true
}
}
lintOptions {
abortOnError false
}
}

dependencies {
compile project(':thirtyinch')
provided "com.android.support:support-annotations:$supportLibraryVersion"

testCompile "junit:junit:$junitVersion"
testCompile "org.mockito:mockito-core:$mockitoVersion"
testCompile "org.assertj:assertj-core:$assertjVersion"
}

publish {
userOrg = 'passsy'
groupId = 'net.grandcentrix.thirtyinch'
artifactId = 'thirtyinch-logginginterceptor'
uploadName = 'ThirtyInch'
publishVersion = VERSION_NAME
//description = ''
website = 'https://github.com/grandcentrix/ThirtyInch'
}
5 changes: 5 additions & 0 deletions logginginterceptor/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<manifest package="net.grandcentrix.thirtyinch.logginginterceptor">

<application />

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/*
* Copyright (C) 2017 grandcentrix GmbH
* 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 net.grandcentrix.thirtyinch.logginginterceptor;

import net.grandcentrix.thirtyinch.BindViewInterceptor;
import net.grandcentrix.thirtyinch.TiLog;
import net.grandcentrix.thirtyinch.TiView;
import net.grandcentrix.thirtyinch.util.AbstractInvocationHandler;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

import static net.grandcentrix.thirtyinch.util.AnnotationUtil.getInterfaceOfClassExtendingGivenInterface;

/**
* Logs all methods calls and parameters to the bound view interface.
*/
public class LoggingInterceptor implements BindViewInterceptor {

private final static class MethodLoggingInvocationHandler<V> extends AbstractInvocationHandler {

/**
* limit each argument instead of the complete string. This should limit the overall
* output to a reasonable length while showing all params
*/
private static final int MAX_LENGTH_OF_PARAM = 240;

private TiLog.Logger mLogger;

private final V mView;

private MethodLoggingInvocationHandler(V view, @NonNull TiLog.Logger logger) {
mView = view;
mLogger = logger;
}

@Override
public String toString() {
return "MethodLoggingProxy@" + Integer.toHexString(this.hashCode()) + "-" + mView
.toString();
}

@Override
protected Object handleInvocation(final Object proxy, final Method method,
final Object[] args)
throws Throwable {

try {
mLogger.log(Log.VERBOSE, TAG, toString(method, args));
return method.invoke(mView, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}

private static String parseParams(Object[] methodParams, int maxLenOfParam) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < methodParams.length; i++) {
final Object param = methodParams[i];

final String paramString;
if (param instanceof List) {
final int size = ((List) param).size();
final String stringPresentation = String.valueOf(param);
paramString = "{" + param.getClass().getSimpleName()
+ "[" + size + "]"
+ "@" + Integer.toHexString(param.hashCode()) + "}"
+ " " + stringPresentation;
} else if (param instanceof Object[]) {
final Object[] args = ((Object[]) param);
final int size = args.length;

final StringBuilder sb = new StringBuilder();
sb.append("[");
for (int j = 0; j < args.length; j++) {
sb.append(String.valueOf(args[j]));
if (j + 1 < args.length) {
sb.append(", ");
}
}
sb.append("]");

paramString = "{" + param.getClass().getSimpleName()
+ "[" + size + "]"
+ "@" + Integer.toHexString(param.hashCode()) + "}"
+ " " + sb;
} else {
paramString = String.valueOf(param);
}

if (paramString.length() <= maxLenOfParam) {
builder.append(paramString);
} else {
final String shortParam = paramString.substring(0,
Math.min(paramString.length(), maxLenOfParam));
builder.append(shortParam);
// trim remaining whitespace at the end before appending ellipsis
builder = new StringBuilder(builder.toString().trim());
builder.append("…");
}
builder.append(", ");
}

// remove last ", "
int length = builder.length();
builder.delete(length - 2, length);

return builder.toString();
}

private static String toString(@NonNull final Method method,
@Nullable final Object[] args) {
final StringBuilder sb = new StringBuilder(method.getName());
sb.append("(");
if (args != null && args.length > 0) {
final String paramsString = parseParams(args, MAX_LENGTH_OF_PARAM);
sb.append(paramsString);
}
sb.append(")");
return sb.toString();
}
}

private static final String TAG = LoggingInterceptor.class.getSimpleName();

private final TiLog.Logger mLogger;

/**
* Logs all view interface method invocations to {@link TiLog}. You may have to enable
* logging from {@link TiLog} or set your own logger with {@link LoggingInterceptor#LoggingInterceptor(TiLog.Logger)}
*/
public LoggingInterceptor() {
this(TiLog.TI_LOG);
}

/**
* Logs all view interface method invocations to the provided {@link TiLog.Logger} interface
*
* @param logger custom logger, {@link TiLog#LOGCAT} or {@link TiLog#NOOP} to disable logging.
*/
public LoggingInterceptor(@Nullable final TiLog.Logger logger) {
if (logger == null) {
mLogger = TiLog.NOOP;
} else {
mLogger = logger;
}
}

@Override
public <V extends TiView> V intercept(final V view) {
if (mLogger != TiLog.NOOP) {
final V wrapped = wrap(view);
TiLog.v(TAG, "wrapping View " + view + " in " + wrapped);
return wrapped;
}
return view;
}

@SuppressWarnings("unchecked")
private <V extends TiView> V wrap(final V view) {

Class<?> foundInterfaceClass = getInterfaceOfClassExtendingGivenInterface(
view.getClass(), TiView.class);
if (foundInterfaceClass == null) {
throw new IllegalStateException("the interface extending TiView could not be found");
}

final V wrappedView = (V) Proxy.newProxyInstance(
foundInterfaceClass.getClassLoader(), new Class<?>[]{foundInterfaceClass},
new MethodLoggingInvocationHandler<>(view, mLogger));

return wrappedView;
}
}
Loading

0 comments on commit fb7d993

Please sign in to comment.