Skip to content

Abelzzg/AOP_LOG_CONNECTOR

Repository files navigation

#应用分析--日志采集 ##传统的应用信息采集

数据采集一般都离不开埋点插桩,但是大多数采集功能都需要手动地插入代码,标识某段操作的起点和终点。例如信息流的下拉刷新,工程师可以在第一个触摸事件时插入开始标记,然后在屏幕更新后插入结束标记。这种方法和Android Systrace工具所提供的功能类似。

友盟的收集方式,都是通过调用代码来实现:

public void onResume() {
	super.onResume();
	MobclickAgent.onResume(this);
}
public void onPause() {
	super.onPause();
	MobclickAgent.onPause(this);
}

MobclickAgent.onProfileSignIn("userID");

MobclickAgent.onProfileSignIn("WB","userID");

甚至连错误统计都需要开发人员去主动调用代码
MobclickAgent.setCatchUncaughtExceptions(false); 

public static void reportError(Context context, String error)   
//或  
public static void reportError(Context context, Throwable e)

这种方法有诸多弊端:

  • 开发者插桩的粒度决定了数据的详细程度,并导致这种方法只能检测可以预见的性能影响。比如,网络连接和响应的渲染通常会被列入数据采集需求中,但其中可能触发磁盘写入,而这个会严重拖慢速度,但你不一定会想起收集数据;
  • Android应用经常使用多线程编程,用户交互的高度异步特点,导致很难彻底检测代码。你必须给应用中的子线程分配唯一识别符以保证数据的完整,而异步让采集器的回收变得困难;
  • 最后,一般应用的开发速度很快,代码变更很频繁,这让插入的标记也必须经常变动,而且手动插入性能检测点非常耗时且容易出错。工程师的时间不应该花费在可以自动化的事情上。而且,在一个不断变化的代码库中,确保这类检测点的正确性需要做大量的工作。

image

##在android采用AOP切面技术采集数据 参考了github上AOP在Android实现切面的项目AOPforAndroid。在这里做一下简单说明:在程序运行的各个需要记录的节点进行切点的切入,记录日志的动作会在切点中进行。

image

这些切点其实是在在编译的时候通过特殊的编译程序aspectj编织进去的.程序编译完成之后,切点里就会有执行日志采集的代码。

image

这个项目旨在解决以上代码侵入和维护困难等问题,使用了aspect的一个gradle插件,和aspect用于向android框架织入切点的jar包,gradle配置如下:

import com.android.build.gradle.LibraryPlugin
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
 
buildscript {
  repositories {
	mavenCentral()
  }
  dependencies {
	classpath 'com.android.tools.build:gradle:0.12.+'
	classpath 'org.aspectj:aspectjtools:1.8.1'
  }
}

apply plugin: 'android-library'

repositories {
  mavenCentral()
}
 
dependencies {
  compile 'org.aspectj:aspectjrt:1.8.1'
}
 
android {
  compileSdkVersion 19
  buildToolsVersion '19.1.0'
 
  lintOptions {
    abortOnError false
  }
}

android.libraryVariants.all { variant ->
  LibraryPlugin plugin = project.plugins.getPlugin(LibraryPlugin)
  JavaCompile javaCompile = variant.javaCompile
  javaCompile.doLast {
    String[] args = ["-showWeaveInfo",
                     "-1.5",
                     "-inpath", javaCompile.destinationDir.toString(),
                     "-aspectpath", javaCompile.classpath.asPath,
                     "-d", javaCompile.destinationDir.toString(),
                     "-classpath", javaCompile.classpath.asPath,
                     "-bootclasspath", plugin.project.android.bootClasspath.join(File.pathSeparator)]

  MessageHandler handler = new MessageHandler(true);
  new Main().run(args, handler)

  def log = project.logger
  for (IMessage message : handler.getMessages(null, true)) {
    switch (message.getKind()) {
      case IMessage.ABORT:
      case IMessage.ERROR:
      case IMessage.FAIL:
        log.error message.message, message.thrown
        break;
      case IMessage.WARNING:
      case IMessage.INFO:
        log.info message.message, message.thrown
        break;
      case IMessage.DEBUG:
        log.debug message.message, message.thrown
        break;
    }
   }
  }
}

在项目中暂时只提供三种切面方式作为示例,大家可以根据自己项目需求定制自己的切面方式。

#####BehaviorAspect--用户行为

private static final String POINTCUT_METHOD1 ="execution(* android.view.View.OnClickListener .*(..))";

private static final String POINTCUT_METHOD0 ="execution(* android.view.View.OnLongClickListener .*(..))";

private static final String POINTCUT_METHOD2 ="execution(* android.app.Activity.onResume(..))";

private static final String POINTCUT_METHOD3 ="execution(* android.app.Activity.onPause(..))";

#####CustomerAspect--定制切面

定制切面,首先需要注册一个注解提供给开发人员使用:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.CONSTRUCTOR, ElementType.METHOD })
public @interface CustomerTrace {
    String eventId();
    String eventName();
}

定制切面的使用 @CustomerTrace(eventName = "定制事件",eventId = "dingzhishijian") public void emptymethod(){ }

然后切点指向注解标注的方法:

private static final String POINTCUT_METHOD = 	"execution(@com.abel.logservice.annotation.CustomerTrace * *(..))";

private static final String POINTCUT_CONSTRUCTOR = 	"execution(@com.abel.logservice.annotation.CustomerTrace *.new(..))";

#####TimeAspect--应用耗时行为切面

应用耗时行为切面,环切切点的方法,记录方法调用使用的时间:

private static final String POINTCUT_METHOD = "execution(* android.app.Activity.onCreate(..))";
        
private static final String POINTCUT_METHOD1 = "execution(* android.app.Fragment.onCreateView(..))";

耗时操作的注解必须是@Around,执行代码中需要调用processd方法,不然程序会卡住不执行。 @Around("methodAnnotatedWithTimeTrace() || methodAnnotatedWithTimeTrace1()") public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); String className = methodSignature.getDeclaringType().getName(); String methodName = methodSignature.getName(); LogReceiverUtils.generateBehaviorEventlog(buildLogMessage(className,methodName)); final StopWatch stopWatch = new StopWatch(); stopWatch.start(); Object result = joinPoint.proceed(); stopWatch.stop(); LogReceiverUtils.generateDuringEventlog(className, methodName, String.valueOf(stopWatch.getTotalTimeMillis())); return result; }

#####日志发送记录模板

日志的记录和发送策略在这里不做详细说明,大家可以参考友盟和bugtags,策略宗旨就是不影响用户APP的使用,不占用过多流量,最好将日志压缩存储,当处于高速网络时发送。

#关于作者 邮箱:[email protected] [email protected](非诚勿扰) 脉脉:Abelzzg

About

aop for android log connect

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages