If I had to give a very quick summary of pros and cons of different approaches:
1- A global NativeList/Queue of events
Pros: Simple and decently efficient.
Cons: Not as efficient as approach #2 if you need to create events in parallel, and not as efficient as approach #3 if your events need to look up more than 1 component on their target entity. Also, you'll have to deal with dependency management manually.
2- NativeStreams of events
Pros: Best parallel write performance.
Cons: They can be a bit of a pain to manage, because each parallel job that wants to create events in parallel might need to create and manage its own NativeStream. And like approach #1, it may still not be as efficient as approach #3 if your events need to look up more than 1 component on their target entity.
3- DynamicBuffer of events on entities that "receive" these events
Pros: Pretty simple, and might have the best performance if your events need multiple component data access on their target entity (avoids component lookups).
Cons: Can't safely create events in parallel, unless they are produced by the same entity
4- Singleton DynamicBuffer of events
Pros: Similar to approach #1 but the dependency management is automatic.
Cons: Unless you go through the trouble of getting the buffer of events once per chunk instead of once per iterated entity, they might be expensive (need to get buffer from lookup every time).
5- Entities as events
Pros: Probably the simplest and most versatile, due to being able to use composition for events.
Cons: Probably the worst-performing of the approaches.
6- Enableable components as events
Pros: Great performance and simplicity if your use case allows using this approach.
Cons: They're only viable if you'll have at most 1 event per frame, or if you may have many events but you don't need per-event data and just need to know if at least one event happened.