Skip to content

debug: Long strings in debugger get truncated #1318

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

Closed
mattwelke opened this issue Mar 12, 2021 · 13 comments
Closed

debug: Long strings in debugger get truncated #1318

mattwelke opened this issue Mar 12, 2021 · 13 comments
Assignees
Labels
Debug Issues related to the debugging functionality of the extension. Documentation FrozenDueToAge

Comments

@mattwelke
Copy link

mattwelke commented Mar 12, 2021

Duplicate issues: #645, #1451

Please answer these questions before submitting your issue. Thanks!

What version of Go, VS Code & VS Code Go extension are you using?

  • Run go version to get version of Go from the VS Code integrated terminal.
    • go version go1.16 linux/amd64
  • Run gopls -v version to get version of Gopls from the VS Code integrated terminal.
    • golang.org/x/tools/gopls v0.6.6
  • Run code -v or code-insiders -v to get version of VS Code or VS Code Insiders.
    • 1.54.1
  • Check your installed extensions to get the version of the VS Code Go extension
    • v0.23.2
  • Run Ctrl+Shift+P (Cmd+Shift+P on Mac OS) > Go: Locate Configured Go Tools command
Checking configured tools....
GOBIN: undefined
toolsGopath: 
gopath: /home/matt/go
GOROOT: /usr/local/go
PATH: /home/matt/.vscode-server/bin/f30a9b73e8ffc278e71575118b6bf568f04587c8/bin:/home/matt/.poetry/bin:/home/matt/google-cloud-sdk/bin:/home/matt/.poetry/bin:/home/matt/.pyenv/plugins/pyenv-virtualenv/shims:/home/matt/.pyenv/shims:/home/matt/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/mnt/c/Program Files/AdoptOpenJDK/jdk-11.0.10.9-hotspot/bin:/mnt/c/Windows/system32:/mnt/c/Windows:/mnt/c/Windows/System32/Wbem:/mnt/c/Windows/System32/WindowsPowerShell/v1.0/:/mnt/c/Windows/System32/OpenSSH/:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Program Files/Git/cmd:/mnt/c/Program Files/dotnet/:/mnt/c/Program Files/Docker/Docker/resources/bin:/mnt/c/ProgramData/DockerDesktop/version-bin:/mnt/c/Users/mattw/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/mattw/AppData/Local/Programs/Microsoft VS Code/bin:/mnt/c/Program Files/AdoptOpenJDK/jdk-11.0.10.9-hotspot/bin:/mnt/c/Users/mattw/.dotnet/tools:/snap/bin:/usr/local/go/bin:/home/matt/go/bin:/home/matt/n/bin:/opt/protoc/bin

   gopkgs: /home/matt/go/bin/gopkgs installed
   go-outline: /home/matt/go/bin/go-outline installed
   gotests: /home/matt/go/bin/gotests installed
   gomodifytags: /home/matt/go/bin/gomodifytags installed
   impl: /home/matt/go/bin/impl installed
   goplay: /home/matt/go/bin/goplay installed
   dlv: /home/matt/go/bin/dlv installed
   staticcheck: staticcheck not installed
   gopls: /home/matt/go/bin/gopls installed

go env
Workspace Folder (beacons-router): /home/matt/code/github.com/groupby/beacons-router
	GO111MODULE=""
	GOARCH="amd64"
	GOBIN=""
	GOCACHE="/home/matt/.cache/go-build"
	GOENV="/home/matt/.config/go/env"
	GOEXE=""
	GOFLAGS=""
	GOHOSTARCH="amd64"
	GOHOSTOS="linux"
	GOINSECURE=""
	GOMODCACHE="/home/matt/go/pkg/mod"
	GONOPROXY="github.com/groupby"
	GONOSUMDB="github.com/groupby"
	GOOS="linux"
	GOPATH="/home/matt/go"
	GOPRIVATE="github.com/groupby"
	GOPROXY="https://proxy.golang.org,direct"
	GOROOT="/usr/local/go"
	GOSUMDB="sum.golang.org"
	GOTMPDIR=""
	GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
	GOVCS=""
	GOVERSION="go1.16"
	GCCGO="gccgo"
	AR="ar"
	CC="gcc"
	CXX="g++"
	CGO_ENABLED="1"
	GOMOD="/home/matt/code/github.com/groupby/beacons-router/go.mod"
	CGO_CFLAGS="-g -O2"
	CGO_CPPFLAGS=""
	CGO_CXXFLAGS="-g -O2"
	CGO_FFLAGS="-g -O2"
	CGO_LDFLAGS="-g -O2"
	PKG_CONFIG="pkg-config"
	GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build1773576749=/tmp/go-build -gno-record-gcc-switches"

Share the Go related settings you have added/edited

Run Preferences: Open Settings (JSON) command to open your settings.json file.
Share all the settings with the go. or ["go"] or gopls prefixes.

(none)

Describe the bug

This issue seems to have resurfaced. It was filed as an issue in the old repo managed by Microsoft and then closed as fixed: microsoft/vscode-go#868

I'm experiencing truncated strings while debugging.

Here it happens when I move my mouse over an error. I'd like to read the entire error (error messages in Go can get quite deep when they're returned from a deep layer of code) but I can't see the root error:

go_vscode_strings_in_debugger_too_short

Steps to reproduce the behavior:

  1. Create a string variable and give it a value that is very long (not sure how long to be honest).
  2. Run debugger.
  3. Try to inspect value. Observe that you can't see all of it.
@hyangah hyangah changed the title Long strings in debugger get truncated debug: Long strings in debugger get truncated Mar 12, 2021
@hyangah
Copy link
Contributor

hyangah commented Mar 12, 2021

Even though not very ideal, how about maxStringLen configuration? That was added as the fix for microsoft/vscode-go#868.

https://github.com/golang/vscode-go/blob/master/docs/debugging.md#configuration

cc @suzmue @polinasok

@hyangah hyangah added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Mar 12, 2021
@mattwelke
Copy link
Author

@hyangah Oh I see. I have to admit I skimmed that issue and just noticed at the bottom that it was closed as fixed. I didn't realize that's how they fixed it. I tried setting it to 10000 characters, which should suit my needs, and it worked well. It still doesn't display the full string in the debugging part of the UI (it has ... now instead of +<num> more) but now when I right click the variable in the debugging part of the UI and click Copy Value, I can paste the full value into a text editor etc instead of only being able to paste the truncated value before. This works well for my workflow. It's rare I need this, it's just that when I do, I need it a lot. xD

Speaking of skimming, I think the fact that I tend to skim through documentation these days is why I missed that instruction in the debugging section of the Go extension documentation. I have experience with multiple programming languages for a few years now, so I tend to assume certain things work the same way, like "this is how one declares a variable", "this is how one starts a debugging session", "this is how one observes the value of the variable while debugging", and with the Go extension, it seems that 3rd example is done differently compared to other languages I've used with VS Code. For example, with JavaScript debugging in VS Code, I don't recall ever encountering this problem.

I'm thinking that a better default setting would be to display a much longer version of the string. I understand that it may not be good for performance to display the entire string every time. But I feel like the current low limit is too low. If performance is a concern, we probably only need to protect the UI's performance from exceptionally long strings, like when someone has a loop and appends to a string making it very long.

If it isn't possible to change the default to be longer, I think something more discoverable would be nice. Maybe something in the UI people can click on to see the full string while they're debugging. I think JetBrains IDEs do it this way. I recall using GoLand and being able to see the full value of my big JSON strings representing data flowing through the program (usually up 10000 characters). I don't recall if they displayed that many characters automatically or if I had to click some sort of "see more".

@hyangah hyangah added Documentation Debug Issues related to the debugging functionality of the extension. DlvDAP and removed WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. labels Mar 15, 2021
@hyangah
Copy link
Contributor

hyangah commented Mar 15, 2021

@mattwelke thanks for sharing the ideas.

I agree that the current state is not ideal.
It is possible that the new debug adapter (dlv dap) may take a completely different approach (either by implementing autoloading or by supporting a custom command to configure the max length dynamically, see go-delve/delve#2144 for the discussion). Note however, UX/UI is mostly controlled by DAP & VS Code (debug adapter protocol) so there will be still limitations.

(Maybe at least we can apply longer limit for the Evaluate Request coming from Debug Console)

I don't know how the current default value was chosen though - some users found large limits affect the performance too much
microsoft/vscode-go#1555 (comment) I hope we can document better so it's more easily discoverable.

@mattwelke
Copy link
Author

@hyangah I like the idea of the longer default limit for evaluate requests coming from the debug console. It's an explicit action from the user, so it's less likely to get in the way and cause performance problems.

There's another ticket we're communicating on related to Go debugging. It's clear to me now that if I want to get deeper into helping with Go debugging, I need to get more familiar with tools like Delve and DAP. I'll revisit this once I've had a chance to do so. :) ty

@polinasok
Copy link
Contributor

The current default is the default in the dlv backend. You can change the limit, but you can't tell delve to load an entire string of arbitrary length at once.

$ dlv debug foo.go 
Type 'help' for list of commands.
(dlv) c
> main.main() ./foo.go:19 (PC: 0x10ce21f)
    14:                 for i := 0; i < 1000; i++ {
    15:                         longstr += "1"
    16:                 }
    17:
    18:                 runtime.Breakpoint()
=>  19:                 fmt.Println(longstr)
    20:         }
    21: }
    22:
    23: func foo() {
    24:         s := `\n123\n`
(dlv) p longstr
"1111111111111111111111111111111111111111111111111111111111111111...+936 more"
(dlv) p longstr[90:]
"1111111111111111111111111111111111111111111111111111111111111111...+846 more"
(dlv) config max-string-len 1000
(dlv) p longstr
"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"

Dlv has built-in loading limits for other types as well.

Dlv-dap can auto-load interfaces, but not other types yet. For strings, we could display the truncated string value by default, but offer an option to expand like we do with compound vars. The expansion would trigger another variables request, which will tell the adapter to load more of the string. At that point, we can either load the entire string chunk by chunk in a loop or change the str limit in dlv, load the whole string, then change the str limit back to the default value. That whole large string would need to be written into a single variables response. Maybe there can be an intermediate partial expansion for really really large values.

We can easily use different default limits for values plugged into the Debug Console. They will also affect WATCH and Copy Value options as those also map to EvaluateRequest.

Debug Adapter Protocol has some fields for "paging of variables", but I don't know if vscode editor actually supports that. But even so, it doesn't sound like this is what is desired here. Having to load thousands of characters in small chunks can get rather annoying.

@polinasok
Copy link
Contributor

We can easily use different default limits for values plugged into the Debug Console. They will also affect WATCH and Copy Value options as those also map to EvaluateRequest.

We get evaluate expressions in the following cases:

  1. entered by user in Debug Console -- "context":"repl"
  2. triggered when the user uses "Copy Value" -- "context":"variables"
  3. automatically generated for expressions under WATCH at each stop -- "context":"watch"

It would make a lot of sense to use a larger string limit when doing (1) and (2), but not (3).

hyangah added a commit to hyangah/delve that referenced this issue Apr 7, 2021
When evaluate requests are triggered in the context of 'repl'
(DEBUG CONSOLE in VSCode) or 'variables' (copy values from VARIABLES
section in VSCode), they are the result of human action and have
more rooms to display. So it is not too bad to apply longer limits.

Variable auto-loading for strings or arrays is nice but currently
it's unclear to me how this should be integrated in the DEBUG
CONSOLE or with the Copy Value feature. Until we have better ideas
and tools, let's go with these larger limits.

Unfortunately, the "Copy Value" from WATCH section triggers evaluate
requests with "watch" context and we don't want to load large data
automatically for "watch". So, users who want to query a large value
should first copy the expression to DEBUG CONSOLE and evaluate it.
Not ideal but not the end of the world either.

Updates golang/vscode-go#1318
hyangah added a commit to hyangah/delve that referenced this issue Apr 7, 2021
When evaluate requests are triggered in the context of 'repl'
(DEBUG CONSOLE in VSCode) or 'variables' (copy values from VARIABLES
section in VSCode), they are the result of human action and have
more rooms to display. So it is not too bad to apply longer limits.

Variable auto-loading for strings or arrays is nice but currently
it's unclear to me how this should be integrated in the DEBUG
CONSOLE or with the Copy Value feature. Until we have better ideas
and tools, let's go with these larger limits.

Unfortunately, the "Copy Value" from WATCH section triggers evaluate
requests with "watch" context and we don't want to load large data
automatically for "watch". So, users who want to query a large value
should first copy the expression to DEBUG CONSOLE and evaluate it.
Not ideal but not the end of the world either.

Updates golang/vscode-go#1318
@gopherbot gopherbot added this to the Untriaged milestone Apr 8, 2021
@hyangah hyangah modified the milestones: Untriaged, Backlog Apr 14, 2021
@JustinGrote
Copy link

JustinGrote commented Apr 26, 2021

This doesn't work for me with dlv-dap

    "go.delveConfig": {
        "dlvLoadConfig": {
            "followPointers": true,
            "maxVariableRecurse": 1,
            "maxStringLen": 300,
            "maxArrayValues": 64,
            "maxStructFields": -1
        },
        "apiVersion": 2,
        "showGlobalVariables": false,
        "debugAdapter": "dlv-dap"
    }

image

EDIT: It's covered in the readme. Legacy works fine: https://github.com/golang/vscode-go/blob/ec0853077c347e3250ff40ac48eaed8daaae4c94/docs/dlv-dap.md

@polinasok
Copy link
Contributor

Yes, These setting are not available in dlv-dap. Please see the discussion at go-delve/delve#2144. We will be looking into ways to load these on demand in dlv-dap.

derekparker pushed a commit to go-delve/delve that referenced this issue May 25, 2021
…s' context (#2418)

* dap: use larger variable load limits in 'repl', 'variables' context

When evaluate requests are triggered in the context of 'repl'
(DEBUG CONSOLE in VSCode) or 'variables' (copy values from VARIABLES
section in VSCode), they are the result of human action and have
more rooms to display. So it is not too bad to apply longer limits.

Variable auto-loading for strings or arrays is nice but currently
it's unclear to me how this should be integrated in the DEBUG
CONSOLE or with the Copy Value feature. Until we have better ideas
and tools, let's go with these larger limits.

Unfortunately, the "Copy Value" from WATCH section triggers evaluate
requests with "watch" context and we don't want to load large data
automatically for "watch". So, users who want to query a large value
should first copy the expression to DEBUG CONSOLE and evaluate it.
Not ideal but not the end of the world either.

Updates golang/vscode-go#1318

* dap: apply large limit only to the string type result

* dap: move string reload logic to convertVariable* where other reload logic is

Currently we are thinking string reload for evaluation as a temporary
workaround until we figure out an intutitive way to present long strings.
So, I hope moving this logic near other reload logic may be better.

And, use the address based expression when reloading - when handling the
function return values, we may not have an expression to use.

* dap: make deep source check happy

* dap: move string reevaluation logic back to onEvaluateRequest

Reloading string variables is tricky if they are in registers.
We don't attempt to reload them but for clarity, move this up
to the onEvaluateRequest handler.

For function call, use a generous limit for string load
since the results are volatile.

* dap: check variable isn't affected by evaluate in other context
@alambertt
Copy link

Go to this settings on VSCode go.delveConfig an set this parameters
image

@mattwelke
Copy link
Author

I added those settings to my VS Code config and ran the debugger again, but it had no effect. However, I do see a popup in the bottom right warning me that it won't have an effect.

Before:

image

After:

image

@mattwelke
Copy link
Author

mattwelke commented Aug 14, 2021

I was able to solve the popup in the bottom right using the instructions in the accepted answer at https://stackoverflow.com/questions/68732514/user-specified-dlvloadconfig-setting-will-be-ignored-by-debug-adapter-dlv-dap.

But then the string doesn't appear correctly under VARIABLES while debugging:

image

The only whitespace is a new line and a tab before the characters:

image

I'm able to see the string contents if I make sure there's no white space before the non-whitespace characters of my string, but it does still get truncated in the hover preview:

image

@polinasok
Copy link
Contributor

@mattwelke, please instead see the stackoverflow answer on the bottom from Hana, who is one of the maintainers of vscode-go.

We are currently transitioning from the legacy adapter ("debugAdapter": "legacy") to the new dlv-dap adapter ("debugAdapter": "dlv-dap"), which was recently enabled by default for local debugging. You do still have the option to switch back to the original debug adapter as the stackoverflow suggested, but we urge you to give the new adapter a full try and let us know of ways we can improve it instead of falling back to the legacy option that we hope to deprecate in a foreseeable future.

The dlv-dap adapter ignores dlvLoadConfig because we are investing in more dynamic and context-based ways of loading data than a single setting that is used for everything in the debug session. Our goal is to create a UI where the user will not miss this setting. Your options for viewing the string currently include:

  • Variables pane value via hover - limit is 512 (we are also considering 1024, which is the editor's hover limit)
    (Note: this limit is the most conservative one because it applies to all strings and can impact the tools' performance)
  • Entering variable's fully qualified name (Copy as Expression) into Debug Console - limit is 4096
  • Copy Value - load limit is 4096
  • Hover over the variable in the source file - limit is 4096

If these automated limits are not sufficient for your case, please let us know.

As for the rendering of the newline, you have come across the difference in how this is handled in the legacy adapter vs the new dlv-dap adapter. This difference is not related to dlvLoadConfig. Please also see #1321.

gopherbot pushed a commit that referenced this issue Aug 25, 2021
Expands the warning and adds FAQ entry.

Updates #1318

Change-Id: Idb74b855d1d7efed997a2b3e7f42127fed2ca8be
GitHub-Last-Rev: 5153c1b
GitHub-Pull-Request: #1715
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/344370
Reviewed-by: Hyang-Ah Hana Kim <[email protected]>
Reviewed-by: Suzy Mueller <[email protected]>
Trust: Hyang-Ah Hana Kim <[email protected]>
Run-TryBot: Hyang-Ah Hana Kim <[email protected]>
TryBot-Result: kokoro <[email protected]>
gopherbot pushed a commit that referenced this issue Aug 30, 2021
…ication

Expands the warning and adds FAQ entry.

Updates #1318

Change-Id: Iecefad6a85c27978c3c25ff9c286e5d37192eaad
GitHub-Last-Rev: 5153c1b
GitHub-Pull-Request: #1715
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/344370
Reviewed-by: Hyang-Ah Hana Kim <[email protected]>
Reviewed-by: Suzy Mueller <[email protected]>
Trust: Hyang-Ah Hana Kim <[email protected]>
Run-TryBot: Hyang-Ah Hana Kim <[email protected]>
TryBot-Result: kokoro <[email protected]>
(cherry picked from commit ebd07b1)
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/346093
@hyangah
Copy link
Contributor

hyangah commented Oct 5, 2021

dlv-dap has been the default debug adapter for a while. @polinasok summarized the current status and limit in #1318 (comment). (thanks!)

If those limits are not sufficient, please open a new issue and what context you want to inspect long strings.

Note though, as @polinasok explained, variables pane value via hover cannot display more than 1024 due to editor's limit even we increase the default or allow users to configure the limit.

Closing.

@hyangah hyangah closed this as completed Oct 5, 2021
@golang golang locked and limited conversation to collaborators Oct 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Debug Issues related to the debugging functionality of the extension. Documentation FrozenDueToAge
Projects
None yet
Development

No branches or pull requests

6 participants