Skip to content

Data Collection Custom Rules

View

Activity

  • First, 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

  • Requires enabling 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 Views
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 Views
            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 Views
                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 Views, 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 a 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 to NOT collect; return false to collect
            return url.startsWith("https://url.rule");
        }
    })
);
FTSdk.initRUMWithConfig(
    FTRUMConfig()
        .setResourceUrlHandler(object : FTInTakeUrlHandler {
            override fun isInTakeUrl(url: String): Boolean {
                // Return true to NOT collect; return false to collect
                return url.startsWith("https://url.rule")
            }
        })
)

Add 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
    }
}   

Filter 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 do 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 do 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. The following uses w3c-traceContext as an example.

 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)
    }
}