This is most often done with your second option, the event system. When something happens, send out an event describing what happened. Anything the HUD cares about it will listen for. It will potentially need to keep copies of some data (like health), but this is often beneficial for a variety of reasons.
One example of why the copy is useful is that you can animate these values. The player health may immediately drop by 10 points but the HUD can flash the health bar, set the lost amount to a different color, and then shrink the bar by the lost amount over some short period of time.
Event-based approach is necessary for some other things, as well. For instance, to display the damage of an attack, you can't just query the state of the game. The attack will quite likely have been fully resolved and forgotten by the time the HUD queries if any attacks are going on. If every attack also emits an event then the HUD and buffer those up and display them during the next HUD update.
Event-based approaches also come in handy in larger scale games. Many games make use of UI middleware with embedded but inefficient scripting languages that often have severe performance concerns when calling between script and C++ code. Letting the C++ code buffer up the events and then dispatch them all to the UI script code in one call can be very beneficial for performance, both bercause it reduces C++-to-script calls and because it is more friendly to the CPU cache.
Athur's answer is a good one for some higher-level languages that already have Observer-like properties built-in. For lower-level code the overhead of making some data observable with a generic framework may not be worth the cost, especially if you still also have an event system (which you need anyway for things that aren't state-based, like the attacks example). We've used observers in some Unity code (non-real-time game) combined with an MVVM pattern for the various HUD components and inventory screens and that worked well. In bigger real-time games we have definitely seen observer and reflection systems take up significant portions of frame time and so I recommend avoiding them and going with a simple event-based architecture since you can optimize that down the road quite easily if you end up needing to.