<commit_before>/*
 * Copyright 2015 NAVER Corp.
 *
 * 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 com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server;

import java.net.Socket;

import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor;
import com.navercorp.pinpoint.bootstrap.context.scope.TraceScope;
import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TTransport;

import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder;
import com.navercorp.pinpoint.bootstrap.context.SpanId;
import com.navercorp.pinpoint.bootstrap.context.SpanRecorder;
import com.navercorp.pinpoint.bootstrap.context.Trace;
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
import com.navercorp.pinpoint.bootstrap.context.TraceId;
import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor;
import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.common.trace.ServiceType;
import com.navercorp.pinpoint.plugin.thrift.ThriftClientCallContext;
import com.navercorp.pinpoint.plugin.thrift.ThriftConstants;
import com.navercorp.pinpoint.plugin.thrift.ThriftRequestProperty;
import com.navercorp.pinpoint.plugin.thrift.ThriftUtils;
import com.navercorp.pinpoint.plugin.thrift.descriptor.ThriftServerEntryMethodDescriptor;
import com.navercorp.pinpoint.plugin.thrift.field.accessor.ServerMarkerFlagFieldAccessor;
import com.navercorp.pinpoint.plugin.thrift.field.accessor.SocketFieldAccessor;

/**
 * This interceptor intercepts the point in which the client message is read, and creates a new trace object to indicate the starting point of a new span.
 * <ul>
 * <li>Synchronous
 * <p>
 * <tt>TBaseProcessorProcessInterceptor</tt> -> <tt>ProcessFunctionProcessInterceptor</tt> -> <tt>TProtocolReadFieldBeginInterceptor</tt> <->
 * <tt>TProtocolReadTTypeInterceptor</tt> -> <b><tt>TProtocolReadMessageEndInterceptor</tt></b></li>
 * <li>Asynchronous
 * <p>
 * <tt>TBaseAsyncProcessorProcessInterceptor</tt> -> <tt>TProtocolReadMessageBeginInterceptor</tt> -> <tt>TProtocolReadFieldBeginInterceptor</tt> <->
 * <tt>TProtocolReadTTypeInterceptor</tt> -> <b><tt>TProtocolReadMessageEndInterceptor</tt></b>
 * </ul>
 * <p>
 * Based on Thrift 0.8.0+
 *
 * @author <NAME>
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.server.TBaseProcessorProcessInterceptor TBaseProcessorProcessInterceptor
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.server.ProcessFunctionProcessInterceptor ProcessFunctionProcessInterceptor
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.server.async.TBaseAsyncProcessorProcessInterceptor TBaseAsyncProcessProcessInterceptor
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadMessageBeginInterceptor TProtocolReadMessageBeginInterceptor
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadFieldBeginInterceptor TProtocolReadFieldBeginInterceptor
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadTTypeInterceptor TProtocolReadTTypeInterceptor
 */
public class TProtocolReadMessageEndInterceptor implements AroundInterceptor {
    private static final String SCOPE_NAME = "##THRIFT_SERVER_PROTOCOL_TRACE";
    private final ThriftServerEntryMethodDescriptor thriftServerEntryMethodDescriptor = new ThriftServerEntryMethodDescriptor();

    private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
    private final boolean isDebug = logger.isDebugEnabled();

    private final TraceContext traceContext;
    private final MethodDescriptor descriptor;
    private final InterceptorScope scope;

    public TProtocolReadMessageEndInterceptor(TraceContext traceContext, MethodDescriptor descriptor, InterceptorScope scope) {
        this.traceContext = traceContext;
        this.descriptor = descriptor;
        this.scope = scope;
        this.traceContext.cacheApi(this.thriftServerEntryMethodDescriptor);
    }

    @Override
    public void before(Object target, Object[] args) {
        if (isDebug) {
            logger.beforeInterceptor(target, args);
        }

        if (!validate(target)) {
            return;
        }

        final InterceptorScopeInvocation currentTransaction = this.scope.getCurrentInvocation();
        if (currentTransaction == null) {
            return;
        }

        final Object attachment = currentTransaction.getAttachment();
        if (attachment instanceof ThriftClientCallContext) {
            ThriftClientCallContext clientCallContext = (ThriftClientCallContext) attachment;
            try {
                if (traceContext.currentRawTraceObject() != null) {
                    // duplicate trace.
                    return;
                }

                // Check if there is an active trace first for cases such as TServlet, which one of the WAS plugins would
                // have created one already.
                ThriftRequestProperty parentTraceInfo = clientCallContext.getTraceHeader();
                this.logger.debug("parentTraceInfo : {}", parentTraceInfo);

                final String methodUri = toMethodUri(clientCallContext);
                final Trace trace = createTrace(target, parentTraceInfo, methodUri);
                clientCallContext.setEntryPoint(true);
                if (trace == null) {
                    return;
                }

                if (!initScope(trace)) {
                    // invalid scope.
                    deleteTrace(trace);
                    return;
                }
                entryScope(trace);

                if (!trace.canSampled()) {
                    return;
                }

                SpanEventRecorder recorder = trace.traceBlockBegin();
                recorder.recordServiceType(ThriftConstants.THRIFT_SERVER_INTERNAL);
                if (methodUri != null) {
                    recorder.recordAttribute(ThriftConstants.THRIFT_URL, methodUri);
                }
            } catch (Throwable t) {
                logger.warn("Error creating trace object. Cause:{}", t.getMessage(), t);
            }
        }
    }

    private String toMethodUri(ThriftClientCallContext clientCallContext) {
        String methodUri = ThriftConstants.UNKNOWN_METHOD_URI;
        final String methodName = clientCallContext.getMethodName();
        final String processName = clientCallContext.getProcessName();
        if (processName != null) {
            StringBuilder sb = new StringBuilder(processName);
            if (!methodUri.endsWith("/")) {
                sb.append("/");
            }
            if (methodName != null) {
                sb.append(methodName);
            }
            methodUri = sb.toString();
        }
        return methodUri;
    }

    @Override
    public void after(Object target, Object[] args, Object result, Throwable throwable) {
        if (isDebug) {
            logger.afterInterceptor(target, args, result, throwable);
        }
<commit_msg>[#8622] Fix thrift methodUri<commit_after>/*
 * Copyright 2015 NAVER Corp.
 *
 * 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 com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server;

import java.net.Socket;

import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor;
import com.navercorp.pinpoint.bootstrap.context.scope.TraceScope;
import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TTransport;

import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder;
import com.navercorp.pinpoint.bootstrap.context.SpanId;
import com.navercorp.pinpoint.bootstrap.context.SpanRecorder;
import com.navercorp.pinpoint.bootstrap.context.Trace;
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
import com.navercorp.pinpoint.bootstrap.context.TraceId;
import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor;
import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.common.trace.ServiceType;
import com.navercorp.pinpoint.plugin.thrift.ThriftClientCallContext;
import com.navercorp.pinpoint.plugin.thrift.ThriftConstants;
import com.navercorp.pinpoint.plugin.thrift.ThriftRequestProperty;
import com.navercorp.pinpoint.plugin.thrift.ThriftUtils;
import com.navercorp.pinpoint.plugin.thrift.descriptor.ThriftServerEntryMethodDescriptor;
import com.navercorp.pinpoint.plugin.thrift.field.accessor.ServerMarkerFlagFieldAccessor;
import com.navercorp.pinpoint.plugin.thrift.field.accessor.SocketFieldAccessor;

/**
 * This interceptor intercepts the point in which the client message is read, and creates a new trace object to indicate the starting point of a new span.
 * <ul>
 * <li>Synchronous
 * <p>
 * <tt>TBaseProcessorProcessInterceptor</tt> -> <tt>ProcessFunctionProcessInterceptor</tt> -> <tt>TProtocolReadFieldBeginInterceptor</tt> <->
 * <tt>TProtocolReadTTypeInterceptor</tt> -> <b><tt>TProtocolReadMessageEndInterceptor</tt></b></li>
 * <li>Asynchronous
 * <p>
 * <tt>TBaseAsyncProcessorProcessInterceptor</tt> -> <tt>TProtocolReadMessageBeginInterceptor</tt> -> <tt>TProtocolReadFieldBeginInterceptor</tt> <->
 * <tt>TProtocolReadTTypeInterceptor</tt> -> <b><tt>TProtocolReadMessageEndInterceptor</tt></b>
 * </ul>
 * <p>
 * Based on Thrift 0.8.0+
 *
 * @author <NAME>
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.server.TBaseProcessorProcessInterceptor TBaseProcessorProcessInterceptor
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.server.ProcessFunctionProcessInterceptor ProcessFunctionProcessInterceptor
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.server.async.TBaseAsyncProcessorProcessInterceptor TBaseAsyncProcessProcessInterceptor
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadMessageBeginInterceptor TProtocolReadMessageBeginInterceptor
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadFieldBeginInterceptor TProtocolReadFieldBeginInterceptor
 * @see com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadTTypeInterceptor TProtocolReadTTypeInterceptor
 */
public class TProtocolReadMessageEndInterceptor implements AroundInterceptor {
    private static final String SCOPE_NAME = "##THRIFT_SERVER_PROTOCOL_TRACE";
    private final ThriftServerEntryMethodDescriptor thriftServerEntryMethodDescriptor = new ThriftServerEntryMethodDescriptor();

    private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
    private final boolean isDebug = logger.isDebugEnabled();

    private final TraceContext traceContext;
    private final MethodDescriptor descriptor;
    private final InterceptorScope scope;

    public TProtocolReadMessageEndInterceptor(TraceContext traceContext, MethodDescriptor descriptor, InterceptorScope scope) {
        this.traceContext = traceContext;
        this.descriptor = descriptor;
        this.scope = scope;
        this.traceContext.cacheApi(this.thriftServerEntryMethodDescriptor);
    }

    @Override
    public void before(Object target, Object[] args) {
        if (isDebug) {
            logger.beforeInterceptor(target, args);
        }

        if (!validate(target)) {
            return;
        }

        final InterceptorScopeInvocation currentTransaction = this.scope.getCurrentInvocation();
        if (currentTransaction == null) {
            return;
        }

        final Object attachment = currentTransaction.getAttachment();
        if (attachment instanceof ThriftClientCallContext) {
            ThriftClientCallContext clientCallContext = (ThriftClientCallContext) attachment;
            try {
                if (traceContext.currentRawTraceObject() != null) {
                    // duplicate trace.
                    return;
                }

                // Check if there is an active trace first for cases such as TServlet, which one of the WAS plugins would
                // have created one already.
                ThriftRequestProperty parentTraceInfo = clientCallContext.getTraceHeader();
                this.logger.debug("parentTraceInfo : {}", parentTraceInfo);

                final String methodUri = toMethodUri(clientCallContext);
                final Trace trace = createTrace(target, parentTraceInfo, methodUri);
                clientCallContext.setEntryPoint(true);
                if (trace == null) {
                    return;
                }

                if (!initScope(trace)) {
                    // invalid scope.
                    deleteTrace(trace);
                    return;
                }
                entryScope(trace);

                if (!trace.canSampled()) {
                    return;
                }

                SpanEventRecorder recorder = trace.traceBlockBegin();
                recorder.recordServiceType(ThriftConstants.THRIFT_SERVER_INTERNAL);
                if (methodUri != null) {
                    recorder.recordAttribute(ThriftConstants.THRIFT_URL, methodUri);
                }
            } catch (Throwable t) {
                logger.warn("Error creating trace object. Cause:{}", t.getMessage(), t);
            }
        }
    }

    private String toMethodUri(ThriftClientCallContext clientCallContext) {
        String methodUri = ThriftConstants.UNKNOWN_METHOD_URI;
        final String methodName = clientCallContext.getMethodName();
        final String processName = clientCallContext.getProcessName();
        if (processName != null) {
            StringBuilder sb = new StringBuilder(processName);
            if (!processName.endsWith("/")) {
                sb.append("/");
            }
            if (methodName != null) {
                sb.append(methodName);
            }
            methodUri = sb.toString();
        }
        return methodUri;
    }

    @Override
    public void after(Object target, Object[] args, Object result, Throwable throwable) {
        if (isDebug) {
            logger.afterInterceptor(target, args, result, throwable);
        }

{'fraction_non_alphanumeric': 0.0889132821075741, 'fraction_numerical': 0.00167882740362885, 'mean_word_length': 3.3142061281337045, 'pattern_counts': {'":': 0, '<': 73, '<?xml version=': 0, '>': 85, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1470856', 'n_tokens_mistral': 4134, 'n_tokens_neox': 4012, 'n_words': 839}