-
-
Notifications
You must be signed in to change notification settings - Fork 314
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DAP logging: Allow sending tracing
data to DAP client Debug Console
#2457
Conversation
I'm not agains cleaning this up but I think it would be nice if we could figure out @Yatekii's difficulties logging probe-rs events to vscode in this same PR. Reading through the changes, maybe this addresses the technicalities, but we should probably address the expectations, too. |
As far as I know, there are two problems:
|
@bugadani Can you clarify what you mean by this please? |
My (and Noah's and maybe more people's) expectation is that setting |
There are two tracing subscribers.
Before the log to file was introduced, we used to log to the Debug Console. We can revert to that for (c) ... what do you think? |
I think that sounds reasonable, especially if we document that setting any of the options disables log-to-console |
tracing
data to DAP client Debug Console
@bugadani If you want to manually test this during review, please use the VS Code changes from probe-rs/vscode#94. Older versions should still work, but some messages will be duplicated. |
let read_from_log = self.buffer_file_handle()?; | ||
let mut tracing_log_handle = BufReader::new(read_from_log.try_clone()?); | ||
std::io::Seek::seek(&mut tracing_log_handle, self.seek_pointer)?; | ||
let mut buffer_lines = tracing_log_handle.lines(); | ||
while let Some(Ok(next_line)) = buffer_lines.next() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I understand what this wants to be, but I also think this is worth factoring out into its own function. The difference between flush
and flush_to_dap
is (or... seems to be) what happens with the log lines, and that single line could be passed in as a closure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried that, but it means that I have to pass an Option<DebugAdapter<P>>
to the combined flush
function. That isn't a problem in itself, but the compiler wants you to add a type when you pass a None
value, and for the life of me I couldn't make the syntax work. If you can make it work (you probably can), I'd appreciate the solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
None::<type>
:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That being said I'm not sure we understand each other here, so this can go in as-is, and we can tackle this part later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It requires all the generics in the type, and I can't remember what the error was, but it doesn't like None::<DapAdapter<P>>
... or any of the variants I could come up with :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I've said, I'm not sure at all what you're planning or why it needs a None. If you pass in a closure as I've suggested, the closure captures debug_adapter
for you if you need to use it.
/// and will be automatically removed by the OS when the last handle to it is closed. | ||
/// - When the DAP server is running, the tracing messages are sent to the console. | ||
/// - When the DAP server exits, the remaining messages in this buffer are sent to `stderr`. | ||
buffer_file: Mutex<File>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this have to be inside a mutex, if we're just cloning the file descriptor? We could save a lock
, a try_clone
and a bunch of error handling if this was just a File
and if buffer_file_handle
returned a &File
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The buffer file is used by the tracing
implementation to write the logs to, as well as by the DebugLogger
for both writing and reading. I need the lock so that I can write to the file, and then update the read pointer to make sure a future flush()
knows where the last 'un-read' data was.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need the lock
But you don't! The only .lock()
here is when you clone the FD and the lock is immediately released. What am I not seeing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was not the intention. The intention was to hold onto the lock until I've finished updating the read pointers, but I see now that it is being released. Let me work with it a bit more before we merge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few things:
- I think we should prefer
parking_lot::Mutex
, that does not return an error from lock. I'm not convinced we need to deal with poisoning here. - If you need the lock to stick for a bit, you can return
impl Deref<Target = File>
. That way the user (even if it's just us) doesn't have to know about the lock's internals, but the lock will be held as long as it's needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bugadani I've made the changes to hold onto the MutexGuard
until after I've updated the file pointers. I've done some manual testing with excessive amounts of log data being written to the Debug Console, and all seems to be in order. That said, I'd really appreciate if you can do a sanity check for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation looks to be on the more-complex-than-necessary side at points, but it also seems to be working well, so thanks!
I'm not sure this change deserves about 15 PR's worth of changelog, though 😅
It took a lot of wrangling to get the
Haha ... you know me, I can get a little verbose. I will trim the changelog :) |
c8abb66
to
4d000b2
Compare
/// Try to clone the buffer file handle, so that it can be used by either | ||
/// the DebugAdapter to send messages to the DAP client, or the `tracing` module to record log data. | ||
pub(crate) fn buffer_file_handle(&self) -> Result<File, DebuggerError> { | ||
self.locked_buffer_file()?.try_clone().map_err(|_| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will still allow racy access. If you really think we need the mutex, we should be working with an Arc<Mutex<File>>
and clone the Arc
, not the file.
@bugadani Thank you very much for taking the time to collaborate on this. I feel much better about the quality of this. |
The mechanism of passing messages from the dap_server to the client via stderr is replaced with writing
dap_server
messages and tracing output to the DAP client's Debug Console, using the DAPOutput
event.log-file
parameter.Core::status
were using tracing instrument spans with a default level ofINFO
(obviously caused a lot of noise).