Skip to content

Conversation

@LucaRocco
Copy link

@LucaRocco LucaRocco commented Nov 3, 2025

1. Explain what the PR does

This PR implements what was discussed in this issue (#4887)
The main goal is to improve how Tracee prints and delivers events. Below is the list of the main features included in this PR:

  • Use of streams to send events to multiple destinations. This feature is enabled only through the configuration file. Old flags for simple use cases are still supported.
  • Allow users to reuse the same stream for multiple destinations to optimize resource utilization.
  • Implement congestion control for streams, allowing users to choose between drop and block strategies.

check-pr output:

6865f7b92 **Handle gotemplate in webhookEventPrinter. Extend docs**
90fd199b9 **Improve tests. Update configuration examples**
f1382b748 **Improve tests. Add validation of streams and destinations coming from config file**
59848d0d2 **Implement stream filter by events. Moved code based on responsabilities**
38083a03b **Implement streams and destinations config. Add congestion control to streams channel.**

2. Explain how to test it

Once the implementation is complete, a full test scenario will be provided.
Currently, to test the stream and destination handling, I am using the following configuration file and policies:

config.yaml

output:
  destinations:
    - name: stdoutdestination
      type: file
      path: stdout
      format: json

    - name: filedestination
      type: file
      path: file1
      format: table
    
    - name: webhook-1
      type: webhook
      url: http://192.168.64.1:1090/mock
      format: json
  
  streams:
    - name: catch_all_stream
      destinations: 
        - stdoutdestination
        - filedestination
    - name: anti_debugging_stream
      destinations:
        - webhook-1
      filters:
        policies:
          - webhook-policy
    
  options:
    exec-env: true

json-policy.yaml

apiVersion: tracee.aquasec.com/v1beta1
kind: Policy
metadata:
  annotations:
    description: policy to print on screen
  name: json-policy
spec:
  rules:
    - event: sched_process_exec
  scope:
    - global

webhook-policy.yaml

apiVersion: tracee.aquasec.com/v1beta1
kind: Policy
metadata:
  annotations:
    description: policy to send to a webhook
  name: webhook-policy
spec:
  rules:
    - event: anti_debugging
  scope:
    - global

Command to run Tracee

To run Tracee, I use a variation of the following command (depending on what I want to test, I may add or remove policies and adjust the configuration to match the policies in use)

./dist/tracee --config config.yaml --policy json-policy.yaml --policy webhook-policy.yaml

3. Other comments

Below is a checklist of the implemented and pending features, along with the activities I plan to complete before considering this PR finished:

  • Streams and destinations handling through the configuration file
  • Congestion control (block and drop strategies for streams)
  • Stream filtering by event
  • Support multiple stream creation from CLI
  • Code cleanup
  • Test improvements (if needed)
  • Configuration example update
  • Documentation update

@CLAassistant
Copy link

CLAassistant commented Nov 3, 2025

CLA assistant check
All committers have signed the CLA.

@LucaRocco LucaRocco marked this pull request as draft November 3, 2025 10:19
@LucaRocco LucaRocco force-pushed the message-output-routing branch 3 times, most recently from 776eea3 to 13f9161 Compare November 3, 2025 13:38
@josedonizetti josedonizetti changed the title WIP: Event routing through streams flag(output): new format Nov 4, 2025
@josedonizetti josedonizetti changed the title flag(output): new format flag(output): new flag format Nov 4, 2025
@josedonizetti josedonizetti self-requested a review November 4, 2025 15:21
@codecov
Copy link

codecov bot commented Nov 4, 2025

Codecov Report

❌ Patch coverage is 50.58140% with 255 lines in your changes missing coverage. Please review.
✅ Project coverage is 30.29%. Comparing base (a6e2750) to head (6865f7b).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/cmd/tracee.go 0.00% 42 Missing ⚠️
pkg/cmd/cobra/config.go 74.37% 32 Missing and 9 partials ⚠️
pkg/cmd/printer/printer.go 62.74% 38 Missing ⚠️
pkg/cmd/cobra/cobra.go 0.00% 33 Missing ⚠️
pkg/ebpf/tracee.go 0.00% 26 Missing ⚠️
pkg/cmd/urfave/urfave.go 0.00% 17 Missing ⚠️
pkg/streams/streams.go 46.15% 13 Missing and 1 partial ⚠️
pkg/cmd/printer/broadcast.go 36.84% 12 Missing ⚠️
pkg/server/grpc/tracee.go 0.00% 9 Missing ⚠️
cmd/tracee/cmd/analyze.go 0.00% 7 Missing ⚠️
... and 3 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5008      +/-   ##
==========================================
+ Coverage   29.70%   30.29%   +0.59%     
==========================================
  Files         234      234              
  Lines       26180    26437     +257     
==========================================
+ Hits         7776     8009     +233     
- Misses      17864    17870       +6     
- Partials      540      558      +18     
Flag Coverage Δ
unit 30.29% <50.58%> (+0.59%) ⬆️
Files with missing lines Coverage Δ
pkg/config/config.go 0.00% <0.00%> (ø)
pkg/cmd/flags/output.go 85.57% <91.07%> (+1.94%) ⬆️
cmd/tracee/cmd/analyze.go 31.74% <0.00%> (-0.78%) ⬇️
pkg/cmd/flags/tracee_ebpf_output.go 51.54% <53.33%> (-0.07%) ⬇️
pkg/server/grpc/tracee.go 60.95% <0.00%> (-0.52%) ⬇️
pkg/cmd/printer/broadcast.go 34.14% <36.84%> (+34.14%) ⬆️
pkg/streams/streams.go 66.66% <46.15%> (-12.97%) ⬇️
pkg/cmd/urfave/urfave.go 0.00% <0.00%> (ø)
pkg/ebpf/tracee.go 0.00% <0.00%> (ø)
pkg/cmd/cobra/cobra.go 0.00% <0.00%> (ø)
... and 3 more

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@LucaRocco
Copy link
Author

Hi @josedonizetti,

Thanks for taking care of the PR. The coding part is done. I’ll go through everything again and add a few more tests before requesting a review.

Just a few points:

  • On the gRPC side, I created an empty stream (with only the policy filter), but I think we should improve that part and make the stream configurable (pkg/server/grpc/tracee.go).
  • There are a few comments in the codebase that I left because I’d like to get your opinion on them (for example pkg/streams/streams.go).
  • I had to change the flow of the code for this PR because the way the flags were handled before was completely different. In this case, the new configurations come only from the file. While we’re still keeping the --output flag for basic use cases, I wrote all the necessary code to create the Tracee configuration directly from the structs (without converting the structure into a list of flags and parsing them). Let me know what you think.
  • I declared two sets of structures: one maps the configuration defined by the user in the config file (see here), while the other represents the Tracee configuration. The two sets are very similar, we could unify some of the structs into a common one if you prefer.
  • Lastly, in pkg/cmd/cobra/config.go I’m using a function from pkg/cmd/flags (SetOption), which I had to export to use from another package. Maybe we can move it to a common utility package. Let me know.

Luca

@LucaRocco LucaRocco force-pushed the message-output-routing branch from 73b2958 to 90fd199 Compare November 8, 2025 12:53
@LucaRocco LucaRocco marked this pull request as ready for review November 8, 2025 13:53
Comment on lines +266 to +300
if !isStructured("output") {
outputFlags, err := GetFlagsFromViper("output")
if err != nil {
return runner, err
}

output, err := flags.PrepareOutput(outputFlags)
if err != nil {
return runner, err
}

streams := []config.Stream{}
for _, destination := range output.DestinationConfigs {
streams = append(streams, config.Stream{
Name: destination.Name + "-stream",
Destinations: []config.Destination{destination},
})
}
output.TraceeConfig.Streams = streams

cfg.Output = output.TraceeConfig
} else {
outputConfig, err := GetStructuredOutputConfig()
if err != nil {
return runner, err
}

outputTraceeConfig, err := prepareTraceeConfig(
*outputConfig,
cmd.GetContainerMode(containerFilterEnabled(), cfg.NoContainersEnrich))
if err != nil {
return runner, err
}

cfg.Output = outputTraceeConfig
Copy link
Collaborator

@josedonizetti josedonizetti Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the biggest issue for me here. At least with all PRs for flags I've been creating, we are trying to be consistent with flags and config file.

If we do such, it means, GetFlagsFromViper is already prepared to return the proper outputFlags doesn't matter if structured or not https://github.com/aquasecurity/tracee/blob/main/pkg/cmd/cobra/config.go#L20-L70, which means flags.PrepareOutput can handle both flags and config.

Ideally, we would do the same for output flags.

Can u take a look at how I'm implementing the other flags, for example, a simple one:

https://github.com/josedonizetti/tracee/blob/67c263ca24d942d05dfb48a6775787e21d08b548/pkg/cmd/cobra/cobra.go
https://github.com/josedonizetti/tracee/blob/67c263ca24d942d05dfb48a6775787e21d08b548/pkg/cmd/cobra/config.go

https://github.com/aquasecurity/tracee/pull/5021/files

Let me know if u have any questions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @josedonizetti, thank you for the comment. My idea to implement it this ways came from the discussion I had with @yanivagman. Specifically, I am referring to this.

It is completely fine for me changing the way we handle it but at this point we should decide the form of the flags. Do you have any suggestions? I was thinking something like the following:

--stream stream1 --stream stream1:buffer.size=1024 --stream stream1:buffer.mode=block --stream stream1:destinations=d1,d2 --stream1:filters.policies=p1,p2 --stream1:filters.events=e1,e2

what do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LucaRocco We were thinking of:

--output sort-events (bool flags don't need value)
--output destination.<destination_name>.type= 
--output destination.<destination_name>.path= (for file type) 
--output stream.<stream_name>.destination=<destination_name> 
--output stream.<stream_name>.format= 
--output stream.<stream_name>.fields= 
--output stream.<stream_name>.filters= 
--output stream.<stream_name>.parse-data

So the dotted structure, matches a config file, eg:

output: 
   sort-events: true
   destination:
        <name>:
            type: xx
            path: xx

This is how we are doing for all other flags. WDYT?

Copy link
Collaborator

@yanivagman yanivagman Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only to clarify what I meant in the discussion by "cli flags auto-creates a default stream/destination under the hood" is that we don't need to support more than one stream from the cli.
So I don't think we need stream1, stream2, etc. from the cli, just create one stream and keep the flag simple:
--output stream.destinatios=d1,d2
A user who wants more than one stream can then use the config file.

What do you guys think? Should we support more than one stream from the CLI?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @yanivagman,

The new implementation automatically creates a stream under the hood when an --output <type> flag is specified. Users don’t need to explicitly declare a stream when using the CLI.

If we want this change to continue following the standard configuration flow (StructuredConfig → converted to flags by implementing cliFlagger interface → flags.PrepareOutput), we’ll need to:

  • Define a CLI flag structure that supports the declaration of multiple streams. Currently, the code derives flags from the structured configuration and passes them to the same function that typically parses CLI flags. To maintain this behavior, we must be able to generate flags that support all features available in the configuration file. This is why I decided to separate the two flows.
  • Update flags.PrepareOutput to handle the new flags and generate the corresponding Stream structure.

Let me know if you agree with this approach, and I’ll proceed accordingly. I’m a bit busy this week and next, so I’ll likely be able to work on it in about 10 days.

Thanks everyone, much appreciated!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also fine with supporting more than one stream from the CLI, and I think the syntax Jose suggested is good, as long as it won't overcomplicate things.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can go ahead with supporting multiple streams from CLI, I will keep you posted on the implementation. Let me add a new task in the PR and I put it in draft again.

Thanks

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About the internal implementation, I think having a strandard configuration flow is a good idea. But I'll leave this discussion for you and @josedonizetti .
I just want us to agree about the interface exposed to the user through the CLI.

No worries about the time @LucaRocco, thanks for working on this, looks good!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @josedonizetti,

Will old flags still be available? For example: --output webhook:http://localhost:8080. Keeping both behavior will make the code pretty confusing in my opinion. Do you want me to implement it so that we can decide how to proceed?

@josedonizetti
Copy link
Collaborator

josedonizetti commented Nov 11, 2025

@LucaRocco finished testing this today, great contribution! Thanks! The only consideration for now is indeed to match flags/configfile.

@LucaRocco
Copy link
Author

Hi @josedonizetti thank you for the time you are spending reviewing the PR. Appreciated. Happy that the contribution is valid.

Luca

@LucaRocco LucaRocco marked this pull request as draft November 12, 2025 06:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants