## 6 Troubleshooting of Applications  
The ultimate goal of DT is to monitor application performance, detect malfunctioning microservices, and explain the root causes of problems so that they can be resolved quickly. This is feasible by inspecting the tracing traffic passing through specific microservices, detecting erroneous traces/spans, and trying to explain their origin. Thus, the explainability of ML models is the most crucial property. We consider two highly explainable approaches. One is RIPPER [20], which is state-of-the-art in inductive rule learning [53]. It has important technical characteristics, like supporting missing values and numerical and categorical variables, and multiple classes. We experimented with Weka's RIPPER implementation, or JRip [76]. The application of RIPPER for the inspection of erroneous traces is discussed in [7]. We are not going into such details, but will show the impact of noise reduction on the rules. Next is the Dempster-Shafer classifier considered in [66]. It is a far more complex approach but has interesting implications. One important characteristic is the ability to measure the uncertainty of specific rules. It should be interesting to compare the uncertainties of the same rules before and after the sampling. The analysis of tracing traffic passing through a specific microservice starts with data preprocessing. We transform the trace traffic into tabular data to apply ML algorithms. A single trace shows an individual request passage through the microservices. It contains a series of tagged time intervals known as spans. A span contains metadata known as tags and application tags for better process resolution. The traffic can contain hundreds or thousands of traces with different numbers of spans and tags, which are application-specific. In our examples [7], traces contain the names as trace-IDs, and then after each trace, the list of spans with process names, and after each span, the corresponding tags. During the preprocessing stage, we remove some of the fields containing redundant information, like \"traceID\", \"spanID\", \"startMs\", and many others. It should be very straightforward to denoise trace traffic based on expert knowledge or user feedback. Firstly, we preprocess span names. We make a list of all distinct span names existing in trace traffic and put them as the names of the columns of a dataframe. Then, for each trace (as a row), we verify the names of its spans, and in the corresponding columns, enter value = 1. The other columns contain missing values, as that specific trace does not contain those spans. The entire dataframe consists of ones and missing values. Fortunately, the RIPPER and Dempster-Shafer classifiers ignore those missing values and explain the output based on the existing spans in a trace. Eventually, the number of rows in the dataframe coincides with the number of traces in trace traffic, and the number of columns coincides with the number of distinct spans (processes). We label traces via the tag \"error\", where the value \"true\" indicates that the corresponding trace is erroneous. A missing tag \"error\" indicates that the trace is normal. It can also be useful to construct a column in a dataframe that will indicate the type of trace. Secondly, we construct columns revealing metadata information. We put the metadata value in the corresponding cell, where the row corresponds to the trace and the column corresponds to the distinct metadata name. Tracing traffic passing through a malfunctioning microservice can still contain many traces, even after a series of samplings. In this final stage, we apply the sampling of erroneous traces for reducing the volume and simplifying the application of rule induction methods. We aim to understand how the sampling impacts the rule-generation process regarding precision, recall, or uncertainty. It is worth noting that in this stage, the goal of the sampling is not to preserve all possible types and durations of erroneous traces.