Skip to content

Data Collection Custom Rules

View

Activity

  • First, you need to enable it via FTRUMConfig.setEnableTraceUserView(true)
FTSdk.initRUMWithConfig(new FTRUMConfig()
    .setViewActivityTrackingHandler(new FTViewActivityTrackingHandler() {
        @Override
        public HandlerView resolveHandlerView(Activity activity) {
            String activityName = activity.getClass().getSimpleName();

            // Customize view name based on Activity name
            if (activityName.startsWith("Main")) {
                return new HandlerView("Custom Main Page");
            } else if (activityName.startsWith("Detail")) {
                HashMap<String, Object> properties = new HashMap<>();
                properties.put("extra_key", "extra_value");
                return new HandlerView("Custom Detail Page", properties);
            }

            // Return null to skip tracking
            return null;
        }
    })
);
FTSdk.initRUMWithConfig(
    FTRUMConfig()
        .setViewActivityTrackingHandler(object : FTViewActivityTrackingHandler {
            override fun resolveHandlerView(activity: Activity): HandlerView? {
                val activityName = activity.javaClass.simpleName
                return when {
                    activityName.startsWith("Main") ->
                        HandlerView("Custom Main Page")
                    activityName.startsWith("Detail") -> {
                        val properties = hashMapOf<String, Any>("extra_key" to "extra_value")
                        HandlerView("Custom Detail Page", properties)
                    }
                    else -> null // Skip tracking
                }
            }
        })
)

Fragment

  • You need to enable both FTRUMConfig.setEnableTraceUserView(true) and FTRUMConfig.setEnableTraceUserViewInFragment(true)
FTSdk.initRUMWithConfig(new FTRUMConfig()
    .setViewFragmentTrackingHandler(new FTViewFragmentTrackingHandler() {
        @Override
        public HandlerView resolveHandlerView(FragmentWrapper fragment) {
            String fragmentName = fragment.getSimpleClassName();

            // Customize view name based on Fragment name
            if (fragmentName.equals("HomeFragment")) {
                return new HandlerView("Custom Home Fragment");
            } else if (fragmentName.startsWith("Detail")) {
                HashMap<String, Object> properties = new HashMap<>();
                properties.put("extra_key", "extra_value");
                return new HandlerView("Custom Detail Fragment", properties);
            }

            // Return null to skip tracking
            return null;
        }
    })
);
FTSdk.initRUMWithConfig(
    FTRUMConfig()
        .setViewFragmentTrackingHandler(object : FTViewFragmentTrackingHandler {
            override fun resolveHandlerView(fragment: FragmentWrapper): HandlerView? {
                val fragmentName = fragment.simpleClassName
                return when {
                    fragmentName == "HomeFragment" ->
                        HandlerView("Custom Home Fragment")
                    fragmentName.startsWith("Detail") -> {
                        val properties = hashMapOf<String, Any>("extra_key" to "extra_value")
                        HandlerView("Custom Detail Fragment", properties)
                    }
                    else -> null // Skip tracking
                }
            }
        })
)

Action

  • Requires FTRUMConfig.setEnableTraceUserAction(true) to be enabled
  • Purpose: Customize Action name, properties, or filter Action collection based on specific View
FTSdk.initRUMWithConfig(new FTRUMConfig()
    .setActionTrackingHandler(new FTActionTrackingHandler() {
        @Override
        public HandlerAction resolveHandlerAction(ActionEventWrapper actionEventWrapper) {
            // Get operation type
            ActionSourceType actionType = actionEventWrapper.getSourceType();
            Object source = actionEventWrapper.getSource();

            // Filter Actions for specified View
            if (source instanceof View) {
                View view = (View) source;
                if (view.getId() == R.id.ignore_action_view) {
                    return null;
                }
            }

            // Customize tracking based on operation type
            if (actionType == ActionSourceType.CLICK_VIEW) {
                HashMap<String, Object> properties = new HashMap<>();
                properties.put("extra_key", "extra_value");
                return new HandlerAction("Custom Button Click", properties);
            } else if (actionType == ActionSourceType.CLICK_LIST_ITEM) {
                return new HandlerAction("Custom List Item Click");
            }

            // Return null to skip tracking
            return null;
        }
    })
);
FTSdk.initRUMWithConfig(
    FTRUMConfig()
        .setActionTrackingHandler(object : FTActionTrackingHandler {
            override fun resolveHandlerAction(actionEventWrapper: ActionEventWrapper): HandlerAction? {
                val source = actionEventWrapper.source

                // Filter Actions for specified View
                if (source is View && source.id == R.id.ignore_action_view) {
                    return null
                }

                return when (actionEventWrapper.sourceType) {
                    ActionSourceType.CLICK_VIEW -> {
                        val properties = hashMapOf<String, Any>("extra_key" to "extra_value")
                        HandlerAction("Custom Button Click", properties)
                    }
                    ActionSourceType.CLICK_LIST_ITEM ->
                        HandlerAction("Custom List Item Click")
                    else -> null // Skip tracking
                }
            }
        })
)
Note

You can get the source object of the current operation via ActionEventWrapper.getSource(). For Actions triggered by View, such as normal clicks, list item clicks, Tab clicks, etc., the source is usually the corresponding View. After setting setActionTrackingHandler, the SDK will use the handler's return result as the basis for Action collection. Actions returning null will be skipped; Actions that need to continue collection should return HandlerAction.

Resource

  • Requires FTRUMConfig.setEnableTraceUserResource(true) to be enabled

Collection Filtering Based on Url

FTSdk.initRUMWithConfig(new FTRUMConfig()
    .setResourceUrlHandler(new FTInTakeUrlHandler() {
        @Override
        public boolean isInTakeUrl(String url) {
            // Return true means not collected; return false means collected
            return url.startsWith("https://url.rule");
        }
    })
);
FTSdk.initRUMWithConfig(
    FTRUMConfig()
        .setResourceUrlHandler(object : FTInTakeUrlHandler {
            override fun isInTakeUrl(url: String): Boolean {
                // Return true means not collected; return false means collected
                return url.startsWith("https://url.rule")
            }
        })
)

Adding Custom Properties

Can be done via FTRUMConfig.setOkHttpResourceContentHandler(FTResourceInterceptor.ContentHandlerHelperEx)

new FTResourceInterceptor.ContentHandlerHelperEx() {
    @Override
    public void onRequest(Request request, HashMap<String, Object> extraData) {
        extraData.put("df_custom_key","custom_value");
    }

    @Override
    public void onResponse(Response response, HashMap<String, Object> extraData) throws IOException {
        extraData.put("df_custom_key","custom_value");
    }

    @Override
    public boolean onExceptionWithFilter(Exception e, HashMap<String, Object> extraData)  {
        extraData.put("df_custom_key","custom_value");
        return false;
    }
}
object : FTResourceInterceptor.ContentHandlerHelperEx() {

override fun onRequest(
    request: Request,
    extraData: HashMap<String, Any>
    ) {
        extraData["df_custom_key"] = "custom_value"
    }

    override fun onResponse(
        response: Response,
        extraData: HashMap<String, Any>
    ) {
        extraData["df_custom_key"] = "custom_value"
    }

    override fun onExceptionWithFilter(
        e: Exception,
        extraData: HashMap<String, Any>
    ): Boolean {
        extraData["df_custom_key"] = "custom_value"
        return false
    }
}   

Filtering Network Errors

You can filter local network IOException errors. Can be set via FTRUMConfig.setOkHttpResourceContentHandler(FTResourceInterceptor.ContentHandlerHelperEx), or Custom Resource

new FTResourceInterceptor.ContentHandlerHelperEx() {
    //...

    /**
     * Returns exceptions during network connection
     *
     * @param e         IOException data from the request
     * @param extraData Additional data
     * @return Whether to filter local network errors of type `network_error`. true means filter and not collect
     */
    @Override
    public boolean onExceptionWithFilter(Exception e, HashMap<String, Object> extraData) {
        if (e instanceof SocketTimeoutException) { //Network timeout
            return true;
        }
        return super.onExceptionWithFilter(e, extraData);
    }
}
object : FTResourceInterceptor.ContentHandlerHelperEx() {
    //...

    /**
    * Returns exceptions during network connection
    *
    * @param e         IOException data from the request
    * @param extraData Additional data
    * @return Whether to filter local network errors of type `network_error`. true means override and not collect
    */
    override fun onExceptionWithFilter(e: Exception, extraData: HashMap<String, Any>): Boolean {
        return if (e is SocketTimeoutException) {
            true
        } else {
            super.onExceptionWithFilter(e, extraData)
        }
    }
}

Custom TraceHeader

Can be set via FTTraceConfig.setOkHttpTraceHeaderHandler(FTTraceInterceptor.HeaderHandler), or Custom Trace, using w3c-traceContext as an example below

 new FTTraceInterceptor.HeaderHandler() {
        private String[] splits;

        @Override
        public HashMap<String, String> getTraceHeader(Request request) {
            HashMap<String, String> map = new HashMap<>();
            //Get custom trace_id from header
            String replaceTrace = request.header(CUSTOM_TRACE_HEADER);
            String headerString = FTTraceManager.get().
                    getTraceHeader(request.url().toString())
                    // Get propagation header from header
                    .get(FTTraceHandler.W3C_TRACEPARENT_KEY); 
            splits = headerString.split("-");
            String originTraceId = splits[1];
            splits[1] = replaceTrace;
            map.put(FTTraceHandler.W3C_TRACEPARENT_KEY, headerString.replace(originTraceId, replaceTrace));
            return map;
        }

        @Override
        public String getSpanID() {
            if (splits != null) {
                return splits[2];
            }
            return null;
        }

        @Override
        public String getTraceID() {
            if (splits != null) {
                return splits[1];
            }
            return null;
        }
};
object : FTTraceInterceptor.HeaderHandler() {
    private var splits: List<String>? = null
    override fun getTraceHeader(request: Request): HashMap<String, String> {
        val map = HashMap<String, String>()

        // Get custom trace_id from header
        val replaceTrace = request.header(CUSTOM_TRACE_HEADER)
        val headerString = FTTraceManager.get()
            .getTraceHeader(request.url().toString())
            .get(FTTraceHandler.W3C_TRACEPARENT_KEY)

        splits = headerString?.split("-")
        val originTraceId = splits?.getOrNull(1)

        if (headerString != null && originTraceId != null && replaceTrace != null) {
            map[FTTraceHandler.W3C_TRACEPARENT_KEY] = 
                headerString.replace(originTraceId, replaceTrace)
        }

        return map
    }

    override fun getSpanID(): String? {
        return splits?.getOrNull(2)
    }

    override fun getTraceID(): String? {
        return splits?.getOrNull(1)
    }
}

Associating RUM Resource Using Custom trace_id

If the application side already has a custom trace_id, for example, the request header key is custom_trace_id, you can update the trace_id based on the traceparent generated by the SDK, and specify the trace_id used for RUM Resource association via TraceContext.Simple.

new FTTraceInterceptor.HeaderHandler() {
    @Override
    public TraceContext getTraceContext(Request request) {
        HashMap<String, String> headers = FTTraceManager.get()
                .getTraceHeader(request.url().toString());

        // Get custom trace_id from request header, e.g., custom_trace_id
        String customTraceId = request.header(CUSTOM_TRACE_HEADER);

        TraceContext.Simple sdkContext = TraceContext.Simple.fromTraceType(headers);
        if (customTraceId == null
                || customTraceId.length() == 0
                || sdkContext == null
                || sdkContext.getTraceId() == null) {
            return sdkContext;
        }

        String traceparent = headers.get(FTTraceHandler.W3C_TRACEPARENT_KEY);
        if (traceparent == null) {
            return sdkContext;
        }

        String newTraceparent = traceparent.replace(
                sdkContext.getTraceId(),
                customTraceId
        );

        // Update W3C trace header injected into the request
        headers.put(FTTraceHandler.W3C_TRACEPARENT_KEY, newTraceparent);

        // Optional: Keep custom business header
        headers.put(CUSTOM_TRACE_HEADER, customTraceId);

        // RUM Resource association uses customTraceId, spanId continues to use SDK-generated spanId
        return new TraceContext.Simple(headers, customTraceId, sdkContext.getSpanId());
    }
};
object : FTTraceInterceptor.HeaderHandler() {
    override fun getTraceContext(request: Request): TraceContext? {
        val headers = FTTraceManager.get()
            .getTraceHeader(request.url().toString())

        // Get custom trace_id from request header
        val customTraceId = request.header(CUSTOM_TRACE_HEADER)

        val sdkContext = TraceContext.Simple.fromTraceType(headers)
        val sdkTraceId = sdkContext?.traceId
        val sdkSpanId = sdkContext?.spanId
        if (customTraceId.isNullOrEmpty() || sdkTraceId.isNullOrEmpty()) {
            return sdkContext
        }

        val traceparent = headers[FTTraceHandler.W3C_TRACEPARENT_KEY] ?: return sdkContext
        val newTraceparent = traceparent.replace(sdkTraceId, customTraceId)

        // Update W3C trace header injected into the request
        headers[FTTraceHandler.W3C_TRACEPARENT_KEY] = newTraceparent

        // Optional: Keep custom business header
        headers[CUSTOM_TRACE_HEADER] = customTraceId

        // RUM Resource association uses customTraceId, spanId continues to use SDK-generated spanId
        return TraceContext.Simple(headers, customTraceId, sdkSpanId)
    }
}

Note: W3C trace_id must be a 32-character hexadecimal string and cannot be all 0s.

Feedback

Is this page helpful? ×