1 /* 2 * Copyright 2018, OpenCensus Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.opencensus.contrib.spring.aop; 18 19 import io.opencensus.trace.Tracer; 20 import org.aspectj.lang.ProceedingJoinPoint; 21 import org.aspectj.lang.annotation.Around; 22 import org.aspectj.lang.annotation.Aspect; 23 import org.aspectj.lang.annotation.Pointcut; 24 import org.springframework.beans.factory.annotation.Configurable; 25 26 /** 27 * CensusSpringSqlAspect captures span from all SQL invocations that utilize 28 * java.sql.Statement.execute* 29 * 30 * @since 0.16.0 31 */ 32 @Aspect 33 @Configurable 34 public final class CensusSpringSqlAspect { 35 private final Tracer tracer; 36 37 /** 38 * Creates a {@code CensusSpringSqlAspect} with the given tracer. 39 * 40 * @param tracer the tracer responsible for building new spans 41 * @since 0.16.0 42 */ CensusSpringSqlAspect(Tracer tracer)43 public CensusSpringSqlAspect(Tracer tracer) { 44 this.tracer = tracer; 45 } 46 47 /** 48 * trace handles invocations of java.sql.Statement.execute*. A new span will be created whose name 49 * is (execute|executeQuery|executeQuery)-(hash of sql). 50 * 51 * @since 0.16.0 52 */ 53 @Around("execute() || testing()") trace(ProceedingJoinPoint call)54 public Object trace(ProceedingJoinPoint call) throws Throwable { 55 if (call.getArgs().length == 0 || call.getArgs()[0] == null) { 56 return call.proceed(); 57 } 58 59 String sql = (String) call.getArgs()[0]; 60 String spanName = makeSpanName(call, sql); 61 62 return Handler.proceed(call, tracer, spanName, sql); 63 } 64 65 /** 66 * execute creates spans around all invocations of Statement.execute*. The raw SQL will be stored 67 * in an annotation associated with the Span 68 */ 69 @Pointcut("execution(public !void java.sql.Statement.execute*(java.lang.String))") execute()70 protected void execute() {} 71 72 @Pointcut("execution(public void Sample.execute*(java.lang.String))") testing()73 protected void testing() {} 74 makeSpanName(ProceedingJoinPoint call, String sql)75 private static String makeSpanName(ProceedingJoinPoint call, String sql) { 76 String hash = Integer.toHexString(hashCode(sql.toCharArray())); 77 return call.getSignature().getName() + "-" + hash; 78 } 79 hashCode(char[] seq)80 private static int hashCode(char[] seq) { 81 if (seq == null) { 82 return 0; 83 } 84 85 int hash = 0; 86 for (char c : seq) { 87 hash = 31 * hash + c; 88 } 89 return hash; 90 } 91 } 92