@cryptotaxi247 / kubo / commits / d3cc4ff58

feat: add query functionality to log level command (#10885)

* feat: update log level command to show log levels * test: add log level tests * update TestCommands test * docs: relation to GOLOG_LOG_LEVEL * chore: update to latest go-log * fix: do not output single subsystem name in CLI * test: explicit subsystem request dont output subsystem * LevelFromString renamed to Parse * Modify `ipfs log level` * Denote default level with sdubsystem name '(defult)'. * make "*" an dalias for "all". Test to make sure both work the same.

Russell Dempsey committed Aug 11, 2025 at 15:43 UTC d3cc4ff587e70848bbbf206dc119922791692993
10 files changed +860 -42
cmd/ipfs/kubo/start.go
+2 -2
@@ -214,8 +214,8 @@ func insideGUI() bool {
214 func checkDebug(req *cmds.Request) {
215 // check if user wants to debug. option OR env var.
216 debug, _ := req.Options["debug"].(bool)
217 - ipfsLogLevel, _ := logging.LevelFromString(os.Getenv("IPFS_LOGGING")) // IPFS_LOGGING is deprecated
218 - goLogLevel, _ := logging.LevelFromString(os.Getenv("GOLOG_LOG_LEVEL"))
217 + ipfsLogLevel, _ := logging.Parse(os.Getenv("IPFS_LOGGING")) // IPFS_LOGGING is deprecated
218 + goLogLevel, _ := logging.Parse(os.Getenv("GOLOG_LOG_LEVEL"))
219
220 if debug || goLogLevel == logging.LevelDebug || ipfsLogLevel == logging.LevelDebug {
221 u.Debug = true
core/commands/log.go
+164 -30
@@ -3,16 +3,37 @@ package commands
3 import (
4 "fmt"
5 "io"
6 + "slices"
7
8 cmds "github.com/ipfs/go-ipfs-cmds"
9 logging "github.com/ipfs/go-log/v2"
10 )
11
11 -// Golang os.Args overrides * and replaces the character argument with
12 -// an array which includes every file in the user's CWD. As a
13 -// workaround, we use 'all' instead. The util library still uses * so
14 -// we convert it at this step.
15 -var logAllKeyword = "all"
12 +const (
13 + // allLogSubsystems is used to specify all log subsystems when setting the
14 + // log level.
15 + allLogSubsystems = "*"
16 + // allLogSubsystemsAlias is a convenience alias for allLogSubsystems that
17 + // doesn't require shell escaping.
18 + allLogSubsystemsAlias = "all"
19 + // defaultLogLevel is used to request and to identify the default log
20 + // level.
21 + defaultLogLevel = "default"
22 + // defaultSubsystemKey is the subsystem name that is used to denote the
23 + // default log level. We use parentheses for UI clarity to distinguish it
24 + // from regular subsystem names.
25 + defaultSubsystemKey = "(default)"
26 + // logLevelOption is an option for the tail subcommand to select the log
27 + // level to output.
28 + logLevelOption = "log-level"
29 + // noSubsystemSpecified is used when no subsystem argument is provided
30 + noSubsystemSpecified = ""
31 +)
32 +
33 +type logLevelOutput struct {
34 + Levels map[string]string `json:",omitempty"`
35 + Message string `json:",omitempty"`
36 +}
37
38 var LogCmd = &cmds.Command{
39 Helptext: cmds.HelpText{
@@ -39,46 +60,161 @@ system (not just for the daemon logs, but all commands):
60
61 var logLevelCmd = &cmds.Command{
62 Helptext: cmds.HelpText{
42 - Tagline: "Change the logging level.",
63 + Tagline: "Change or get the logging level.",
64 ShortDescription: `
44 -Change the verbosity of one or all subsystems log output. This does not affect
45 -the event log.
65 +Get or change the logging level of one or all logging subsystems.
66 +
67 +This command provides a runtime alternative to the GOLOG_LOG_LEVEL
68 +environment variable for debugging and troubleshooting.
69 +
70 +UNDERSTANDING DEFAULT vs '*':
71 +
72 +The "default" level is the fallback used by unconfigured subsystems.
73 +You cannot set the default level directly - it only changes when you use '*'.
74 +
75 +The '*' wildcard represents ALL subsystems including the default level.
76 +Setting '*' changes everything at once, including the default.
77 +
78 +EXAMPLES - Getting levels:
79 +
80 + ipfs log level # Show only the default fallback level
81 + ipfs log level all # Show all subsystem levels (100+ lines)
82 + ipfs log level core # Show level for 'core' subsystem only
83 +
84 +EXAMPLES - Setting levels:
85 +
86 + ipfs log level core debug # Set 'core' to 'debug' (default unchanged)
87 + ipfs log level all info # Set ALL to 'info' (including default)
88 + ipfs log level core default # Reset 'core' to use current default level
89 +
90 +WILDCARD OPTIONS:
91 +
92 +Use 'all' (convenient) or '*' (requires escaping) to affect all subsystems:
93 + ipfs log level all debug # Convenient - no shell escaping needed
94 + ipfs log level '*' debug # Equivalent but needs quotes: '*' or "*" or \*
95 +
96 +BEHAVIOR EXAMPLES:
97 +
98 +Initial state (all using default 'error'):
99 + $ ipfs log level => error
100 + $ ipfs log level core => error
101 +
102 +After setting one subsystem:
103 + $ ipfs log level core debug
104 + $ ipfs log level => error (default unchanged!)
105 + $ ipfs log level core => debug (explicitly set)
106 + $ ipfs log level dht => error (still uses default)
107 +
108 +After setting everything with 'all':
109 + $ ipfs log level all info
110 + $ ipfs log level => info (default changed!)
111 + $ ipfs log level core => info (all changed)
112 + $ ipfs log level dht => info (all changed)
113 +
114 +The 'default' keyword always refers to the current default level:
115 + $ ipfs log level => error
116 + $ ipfs log level core default # Sets core to 'error'
117 + $ ipfs log level all info # Changes default to 'info'
118 + $ ipfs log level core default # Now sets core to 'info'
119 `,
120 },
121
122 Arguments: []cmds.Argument{
50 - // TODO use a different keyword for 'all' because all can theoretically
51 - // clash with a subsystem name
52 - cmds.StringArg("subsystem", true, false, fmt.Sprintf("The subsystem logging identifier. Use '%s' for all subsystems.", logAllKeyword)),
53 - cmds.StringArg("level", true, false, `The log level, with 'debug' the most verbose and 'fatal' the least verbose.
54 - One of: debug, info, warn, error, dpanic, panic, fatal.
55 - `),
123 + cmds.StringArg("subsystem", false, false, fmt.Sprintf("The subsystem logging identifier. Use '%s' or '%s' to get or set the log level of all subsystems including the default. If not specified, only show the default log level.", allLogSubsystemsAlias, allLogSubsystems)),
124 + cmds.StringArg("level", false, false, fmt.Sprintf("The log level, with 'debug' as the most verbose and 'fatal' the least verbose. Use '%s' to set to the current default level. One of: debug, info, warn, error, dpanic, panic, fatal, %s", defaultLogLevel, defaultLogLevel)),
125 },
126 NoLocal: true,
127 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
59 - args := req.Arguments
60 - subsystem, level := args[0], args[1]
128 + var level, subsystem string
129
62 - if subsystem == logAllKeyword {
63 - subsystem = "*"
130 + if len(req.Arguments) > 0 {
131 + subsystem = req.Arguments[0]
132 + if len(req.Arguments) > 1 {
133 + level = req.Arguments[1]
134 + }
135 +
136 + // Normalize aliases to the canonical "*" form
137 + if subsystem == allLogSubsystems || subsystem == allLogSubsystemsAlias {
138 + subsystem = "*"
139 + }
140 }
141
66 - if err := logging.SetLogLevel(subsystem, level); err != nil {
67 - return err
142 + // If a level is specified, then set the log level.
143 + if level != "" {
144 + if level == defaultLogLevel {
145 + level = logging.DefaultLevel().String()
146 + }
147 +
148 + if err := logging.SetLogLevel(subsystem, level); err != nil {
149 + return err
150 + }
151 +
152 + s := fmt.Sprintf("Changed log level of '%s' to '%s'\n", subsystem, level)
153 + log.Info(s)
154 +
155 + return cmds.EmitOnce(res, &logLevelOutput{Message: s})
156 }
157
70 - s := fmt.Sprintf("Changed log level of '%s' to '%s'\n", subsystem, level)
71 - log.Info(s)
158 + // Get the level for the requested subsystem.
159 + switch subsystem {
160 + case noSubsystemSpecified:
161 + // Return the default log level
162 + levelMap := map[string]string{logging.DefaultName: logging.DefaultLevel().String()}
163 + return cmds.EmitOnce(res, &logLevelOutput{Levels: levelMap})
164 + case allLogSubsystems, allLogSubsystemsAlias:
165 + // Return levels for all subsystems (default behavior)
166 + levels := logging.SubsystemLevelNames()
167 +
168 + // Replace default subsystem key with defaultSubsystemKey.
169 + levels[defaultSubsystemKey] = levels[logging.DefaultName]
170 + delete(levels, logging.DefaultName)
171 + return cmds.EmitOnce(res, &logLevelOutput{Levels: levels})
172 + default:
173 + // Return level for a specific subsystem.
174 + level, err := logging.SubsystemLevelName(subsystem)
175 + if err != nil {
176 + return err
177 + }
178 + levelMap := map[string]string{subsystem: level}
179 + return cmds.EmitOnce(res, &logLevelOutput{Levels: levelMap})
180 + }
181
73 - return cmds.EmitOnce(res, &MessageOutput{s})
182 },
183 Encoders: cmds.EncoderMap{
76 - cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *MessageOutput) error {
77 - fmt.Fprint(w, out.Message)
184 + cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *logLevelOutput) error {
185 + if out.Message != "" {
186 + fmt.Fprint(w, out.Message)
187 + return nil
188 + }
189 +
190 + // Check if this is an RPC call by looking for the encoding option
191 + encoding, _ := req.Options["encoding"].(string)
192 + isRPC := encoding == "json"
193 +
194 + // Determine whether to show subsystem names in output.
195 + // Show subsystem names when:
196 + // 1. It's an RPC call (needs JSON structure with named fields)
197 + // 2. Multiple subsystems are displayed (for clarity when showing many levels)
198 + showNames := isRPC || len(out.Levels) > 1
199 +
200 + levelNames := make([]string, 0, len(out.Levels))
201 + for subsystem, level := range out.Levels {
202 + if showNames {
203 + // Show subsystem name when it's RPC or when showing multiple subsystems
204 + levelNames = append(levelNames, fmt.Sprintf("%s: %s", subsystem, level))
205 + } else {
206 + // For CLI calls with single subsystem, only show the level
207 + levelNames = append(levelNames, level)
208 + }
209 + }
210 + slices.Sort(levelNames)
211 + for _, ln := range levelNames {
212 + fmt.Fprintln(w, ln)
213 + }
214 return nil
215 }),
216 },
81 - Type: MessageOutput{},
217 + Type: logLevelOutput{},
218 }
219
220 var logLsCmd = &cmds.Command{
@@ -103,12 +239,10 @@ subsystems of a running daemon.
239 Type: stringList{},
240 }
241
106 -const logLevelOption = "log-level"
107 -
242 var logTailCmd = &cmds.Command{
243 Status: cmds.Experimental,
244 Helptext: cmds.HelpText{
111 - Tagline: "Read and outpt log messages.",
245 + Tagline: "Read and output log messages.",
246 ShortDescription: `
247 Outputs log messages as they are generated.
248
@@ -130,7 +264,7 @@ This will only return 'info' logs from bitswap and skip 'debug'.
264 var pipeReader *logging.PipeReader
265 logLevelString, _ := req.Options[logLevelOption].(string)
266 if logLevelString != "" {
133 - logLevel, err := logging.LevelFromString(logLevelString)
267 + logLevel, err := logging.Parse(logLevelString)
268 if err != nil {
269 return fmt.Errorf("setting log level %s: %w", logLevelString, err)
270 }
docs/changelogs/v0.37.md
+22 -1
@@ -11,7 +11,8 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team.
11 - [Overview](#overview)
12 - [🔦 Highlights](#-highlights)
13 - [Clear provide queue when reprovide strategy changes](#clear-provide-queue-when-reprovide-strategy-changes)
14 - - [Named pins in `ipfs add` command](#-named-pins-in-ipfs-add-command)
14 + - [🪵 Revamped `ipfs log level` command](#-revamped-ipfs-log-level-command)
15 + - [📌 Named pins in `ipfs add` command](#-named-pins-in-ipfs-add-command)
16 - [⚙️ `Reprovider.Strategy` is now consistently respected](#-reprovider-strategy-is-now-consistently-respected)
17 - [Removed unnecessary dependencies](#removed-unnecessary-dependencies)
18 - [Deprecated `ipfs stats reprovide`](#deprecated-ipfs-stats-reprovide)
@@ -34,6 +35,26 @@ A new `ipfs provide clear` command also allows manual queue clearing for debuggi
35 > [!NOTE]
36 > Upgrading to Kubo 0.37 will automatically clear any preexisting provide queue. The next time `Reprovider.Interval` hits, `Reprovider.Strategy` will be executed on a clean slate, ensuring consistent behavior with your current configuration.
37
38 +#### 🪵 Revamped `ipfs log level` command
39 +
40 +The `ipfs log level` command has been completely revamped to support both getting and setting log levels with a unified interface.
41 +
42 +**New: Getting log levels**
43 +
44 +- `ipfs log level` - Shows default level only
45 +- `ipfs log level all` - Shows log level for every subsystem, including default level
46 +- `ipfs log level foo` - Shows log level for a specific subsystem only
47 +- Kubo RPC API: `POST /api/v0/log/level?arg=<subsystem>`
48 +
49 +**Enhanced: Setting log levels**
50 +
51 +- `ipfs log level foo debug` - Sets "foo" subsystem to "debug" level
52 +- `ipfs log level all info` - Sets all subsystems to "info" level (convenient, no escaping)
53 +- `ipfs log level '*' info` - Equivalent to above but requires shell escaping
54 +- `ipfs log level foo default` - Sets "foo" subsystem to current default level
55 +
56 +The command now provides full visibility into your current logging configuration while maintaining full backward compatibility. Both `all` and `*` work for specifying all subsystems, with `all` being more convenient since it doesn't require shell escaping.
57 +
58 #### 🧷 Named pins in `ipfs add` command
59
60 Added `--pin-name` flag to `ipfs add` for assigning names to pins.
docs/examples/kubo-as-a-library/go.mod
+1 -1
@@ -90,7 +90,7 @@ require (
90 github.com/ipfs/go-ipld-format v0.6.2 // indirect
91 github.com/ipfs/go-ipld-git v0.1.1 // indirect
92 github.com/ipfs/go-ipld-legacy v0.2.2 // indirect
93 - github.com/ipfs/go-log/v2 v2.6.0 // indirect
93 + github.com/ipfs/go-log/v2 v2.8.0 // indirect
94 github.com/ipfs/go-metrics-interface v0.3.0 // indirect
95 github.com/ipfs/go-peertaskqueue v0.8.2 // indirect
96 github.com/ipfs/go-unixfsnode v1.10.1 // indirect
docs/examples/kubo-as-a-library/go.sum
+2 -2
@@ -345,8 +345,8 @@ github.com/ipfs/go-ipld-legacy v0.2.2/go.mod h1:hhkj+b3kG9b2BcUNw8IFYAsfeNo8E3U7
345 github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
346 github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
347 github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo=
348 -github.com/ipfs/go-log/v2 v2.6.0 h1:2Nu1KKQQ2ayonKp4MPo6pXCjqw1ULc9iohRqWV5EYqg=
349 -github.com/ipfs/go-log/v2 v2.6.0/go.mod h1:p+Efr3qaY5YXpx9TX7MoLCSEZX5boSWj9wh86P5HJa8=
348 +github.com/ipfs/go-log/v2 v2.8.0 h1:SptNTPJQV3s5EF4FdrTu/yVdOKfGbDgn1EBZx4til2o=
349 +github.com/ipfs/go-log/v2 v2.8.0/go.mod h1:2LEEhdv8BGubPeSFTyzbqhCqrwqxCbuTNTLWqgNAipo=
350 github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU=
351 github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY=
352 github.com/ipfs/go-peertaskqueue v0.8.2 h1:PaHFRaVFdxQk1Qo3OKiHPYjmmusQy7gKQUaL8JDszAU=
go.mod
+1 -1
@@ -39,7 +39,7 @@ require (
39 github.com/ipfs/go-ipld-format v0.6.2
40 github.com/ipfs/go-ipld-git v0.1.1
41 github.com/ipfs/go-ipld-legacy v0.2.2
42 - github.com/ipfs/go-log/v2 v2.6.0
42 + github.com/ipfs/go-log/v2 v2.8.0
43 github.com/ipfs/go-metrics-interface v0.3.0
44 github.com/ipfs/go-metrics-prometheus v0.1.0
45 github.com/ipfs/go-test v0.2.2
go.sum
+2 -2
@@ -414,8 +414,8 @@ github.com/ipfs/go-ipld-legacy v0.2.2/go.mod h1:hhkj+b3kG9b2BcUNw8IFYAsfeNo8E3U7
414 github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
415 github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
416 github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo=
417 -github.com/ipfs/go-log/v2 v2.6.0 h1:2Nu1KKQQ2ayonKp4MPo6pXCjqw1ULc9iohRqWV5EYqg=
418 -github.com/ipfs/go-log/v2 v2.6.0/go.mod h1:p+Efr3qaY5YXpx9TX7MoLCSEZX5boSWj9wh86P5HJa8=
417 +github.com/ipfs/go-log/v2 v2.8.0 h1:SptNTPJQV3s5EF4FdrTu/yVdOKfGbDgn1EBZx4til2o=
418 +github.com/ipfs/go-log/v2 v2.8.0/go.mod h1:2LEEhdv8BGubPeSFTyzbqhCqrwqxCbuTNTLWqgNAipo=
419 github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU=
420 github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY=
421 github.com/ipfs/go-metrics-prometheus v0.1.0 h1:bApWOHkrH3VTBHzTHrZSfq4n4weOZDzZFxUXv+HyKcA=
test/cli/log_level_test.go new
+663
@@ -0,0 +1,663 @@
1 +package cli
2 +
3 +import (
4 + "encoding/json"
5 + "fmt"
6 + "net/http"
7 + "strings"
8 + "testing"
9 +
10 + "github.com/ipfs/kubo/test/cli/harness"
11 + . "github.com/ipfs/kubo/test/cli/testutils"
12 + "github.com/stretchr/testify/assert"
13 + "github.com/stretchr/testify/require"
14 +)
15 +
16 +func TestLogLevel(t *testing.T) {
17 +
18 + t.Run("CLI", func(t *testing.T) {
19 + t.Run("level '*' shows all subsystems", func(t *testing.T) {
20 + t.Parallel()
21 + node := harness.NewT(t).NewNode().Init().StartDaemon()
22 + defer node.StopDaemon()
23 +
24 + expectedSubsystems := getExpectedSubsystems(t, node)
25 +
26 + res := node.IPFS("log", "level", "*")
27 + assert.NoError(t, res.Err)
28 + assert.Empty(t, res.Stderr.Lines())
29 +
30 + actualSubsystems := parseCLIOutput(t, res.Stdout.String())
31 +
32 + // Should show all subsystems plus the (default) entry
33 + assert.GreaterOrEqual(t, len(actualSubsystems), len(expectedSubsystems))
34 +
35 + validateAllSubsystemsPresentCLI(t, expectedSubsystems, actualSubsystems, "CLI output")
36 +
37 + // Should have the (default) entry
38 + _, hasDefault := actualSubsystems["(default)"]
39 + assert.True(t, hasDefault, "Should have '(default)' entry")
40 + })
41 +
42 + t.Run("level 'all' shows all subsystems (alias for '*')", func(t *testing.T) {
43 + t.Parallel()
44 + node := harness.NewT(t).NewNode().Init().StartDaemon()
45 + defer node.StopDaemon()
46 +
47 + expectedSubsystems := getExpectedSubsystems(t, node)
48 +
49 + res := node.IPFS("log", "level", "all")
50 + assert.NoError(t, res.Err)
51 + assert.Empty(t, res.Stderr.Lines())
52 +
53 + actualSubsystems := parseCLIOutput(t, res.Stdout.String())
54 +
55 + // Should show all subsystems plus the (default) entry
56 + assert.GreaterOrEqual(t, len(actualSubsystems), len(expectedSubsystems))
57 +
58 + validateAllSubsystemsPresentCLI(t, expectedSubsystems, actualSubsystems, "CLI output")
59 +
60 + // Should have the (default) entry
61 + _, hasDefault := actualSubsystems["(default)"]
62 + assert.True(t, hasDefault, "Should have '(default)' entry")
63 + })
64 +
65 + t.Run("get level for specific subsystem", func(t *testing.T) {
66 + t.Parallel()
67 + node := harness.NewT(t).NewNode().Init().StartDaemon()
68 + defer node.StopDaemon()
69 +
70 + node.IPFS("log", "level", "core", "debug")
71 + res := node.IPFS("log", "level", "core")
72 + assert.NoError(t, res.Err)
73 + assert.Empty(t, res.Stderr.Lines())
74 +
75 + output := res.Stdout.String()
76 + lines := SplitLines(output)
77 +
78 + assert.Equal(t, 1, len(lines))
79 +
80 + line := strings.TrimSpace(lines[0])
81 + assert.Equal(t, "debug", line)
82 + })
83 +
84 + t.Run("get level with no args returns default level", func(t *testing.T) {
85 + t.Parallel()
86 + node := harness.NewT(t).NewNode().Init().StartDaemon()
87 + defer node.StopDaemon()
88 +
89 + res1 := node.IPFS("log", "level", "*", "fatal")
90 + assert.NoError(t, res1.Err)
91 + assert.Empty(t, res1.Stderr.Lines())
92 +
93 + res := node.IPFS("log", "level")
94 + assert.NoError(t, res.Err)
95 + assert.Equal(t, 0, len(res.Stderr.Lines()))
96 +
97 + output := res.Stdout.String()
98 + lines := SplitLines(output)
99 +
100 + assert.Equal(t, 1, len(lines))
101 +
102 + line := strings.TrimSpace(lines[0])
103 + assert.Equal(t, "fatal", line)
104 + })
105 +
106 + t.Run("get level reflects runtime log level changes", func(t *testing.T) {
107 + t.Parallel()
108 + node := harness.NewT(t).NewNode().Init().StartDaemon("--offline")
109 + defer node.StopDaemon()
110 +
111 + node.IPFS("log", "level", "core", "debug")
112 + res := node.IPFS("log", "level", "core")
113 + assert.NoError(t, res.Err)
114 +
115 + output := res.Stdout.String()
116 + lines := SplitLines(output)
117 +
118 + assert.Equal(t, 1, len(lines))
119 +
120 + line := strings.TrimSpace(lines[0])
121 + assert.Equal(t, "debug", line)
122 + })
123 +
124 + t.Run("get level with non-existent subsystem returns error", func(t *testing.T) {
125 + t.Parallel()
126 + node := harness.NewT(t).NewNode().Init().StartDaemon()
127 + defer node.StopDaemon()
128 +
129 + res := node.RunIPFS("log", "level", "non-existent-subsystem")
130 + assert.Error(t, res.Err)
131 + assert.NotEqual(t, 0, len(res.Stderr.Lines()))
132 + })
133 +
134 + t.Run("set level to 'default' keyword", func(t *testing.T) {
135 + t.Parallel()
136 + node := harness.NewT(t).NewNode().Init().StartDaemon()
137 + defer node.StopDaemon()
138 +
139 + // First set a specific subsystem to a different level
140 + res1 := node.IPFS("log", "level", "core", "debug")
141 + assert.NoError(t, res1.Err)
142 + assert.Contains(t, res1.Stdout.String(), "Changed log level of 'core' to 'debug'")
143 +
144 + // Verify it was set to debug
145 + res2 := node.IPFS("log", "level", "core")
146 + assert.NoError(t, res2.Err)
147 + assert.Equal(t, "debug", strings.TrimSpace(res2.Stdout.String()))
148 +
149 + // Get the current default level (should be 'error' since unchanged)
150 + res3 := node.IPFS("log", "level")
151 + assert.NoError(t, res3.Err)
152 + defaultLevel := strings.TrimSpace(res3.Stdout.String())
153 + assert.Equal(t, "error", defaultLevel, "Default level should be 'error' when unchanged")
154 +
155 + // Now set the subsystem back to default
156 + res4 := node.IPFS("log", "level", "core", "default")
157 + assert.NoError(t, res4.Err)
158 + assert.Contains(t, res4.Stdout.String(), "Changed log level of 'core' to")
159 +
160 + // Verify it's now at the default level (should be 'error')
161 + res5 := node.IPFS("log", "level", "core")
162 + assert.NoError(t, res5.Err)
163 + assert.Equal(t, "error", strings.TrimSpace(res5.Stdout.String()))
164 + })
165 +
166 + t.Run("set all subsystems with 'all' changes default (alias for '*')", func(t *testing.T) {
167 + t.Parallel()
168 + node := harness.NewT(t).NewNode().Init().StartDaemon()
169 + defer node.StopDaemon()
170 +
171 + // Initial state - default should be 'error'
172 + res := node.IPFS("log", "level")
173 + assert.NoError(t, res.Err)
174 + assert.Equal(t, "error", strings.TrimSpace(res.Stdout.String()))
175 +
176 + // Set one subsystem to a different level
177 + res = node.IPFS("log", "level", "core", "debug")
178 + assert.NoError(t, res.Err)
179 +
180 + // Default should still be 'error'
181 + res = node.IPFS("log", "level")
182 + assert.NoError(t, res.Err)
183 + assert.Equal(t, "error", strings.TrimSpace(res.Stdout.String()))
184 +
185 + // Now use 'all' to set everything to 'info'
186 + res = node.IPFS("log", "level", "all", "info")
187 + assert.NoError(t, res.Err)
188 + assert.Contains(t, res.Stdout.String(), "Changed log level of '*' to 'info'")
189 +
190 + // Default should now be 'info'
191 + res = node.IPFS("log", "level")
192 + assert.NoError(t, res.Err)
193 + assert.Equal(t, "info", strings.TrimSpace(res.Stdout.String()))
194 +
195 + // Core should also be 'info' (overwritten by 'all')
196 + res = node.IPFS("log", "level", "core")
197 + assert.NoError(t, res.Err)
198 + assert.Equal(t, "info", strings.TrimSpace(res.Stdout.String()))
199 +
200 + // Any other subsystem should also be 'info'
201 + res = node.IPFS("log", "level", "dht")
202 + assert.NoError(t, res.Err)
203 + assert.Equal(t, "info", strings.TrimSpace(res.Stdout.String()))
204 + })
205 +
206 + t.Run("set all subsystems with '*' changes default", func(t *testing.T) {
207 + t.Parallel()
208 + node := harness.NewT(t).NewNode().Init().StartDaemon()
209 + defer node.StopDaemon()
210 +
211 + // Initial state - default should be 'error'
212 + res := node.IPFS("log", "level")
213 + assert.NoError(t, res.Err)
214 + assert.Equal(t, "error", strings.TrimSpace(res.Stdout.String()))
215 +
216 + // Set one subsystem to a different level
217 + res = node.IPFS("log", "level", "core", "debug")
218 + assert.NoError(t, res.Err)
219 +
220 + // Default should still be 'error'
221 + res = node.IPFS("log", "level")
222 + assert.NoError(t, res.Err)
223 + assert.Equal(t, "error", strings.TrimSpace(res.Stdout.String()))
224 +
225 + // Now use '*' to set everything to 'info'
226 + res = node.IPFS("log", "level", "*", "info")
227 + assert.NoError(t, res.Err)
228 + assert.Contains(t, res.Stdout.String(), "Changed log level of '*' to 'info'")
229 +
230 + // Default should now be 'info'
231 + res = node.IPFS("log", "level")
232 + assert.NoError(t, res.Err)
233 + assert.Equal(t, "info", strings.TrimSpace(res.Stdout.String()))
234 +
235 + // Core should also be 'info' (overwritten by '*')
236 + res = node.IPFS("log", "level", "core")
237 + assert.NoError(t, res.Err)
238 + assert.Equal(t, "info", strings.TrimSpace(res.Stdout.String()))
239 +
240 + // Any other subsystem should also be 'info'
241 + res = node.IPFS("log", "level", "dht")
242 + assert.NoError(t, res.Err)
243 + assert.Equal(t, "info", strings.TrimSpace(res.Stdout.String()))
244 + })
245 +
246 + t.Run("'all' in get mode shows (default) entry (alias for '*')", func(t *testing.T) {
247 + t.Parallel()
248 + node := harness.NewT(t).NewNode().Init().StartDaemon()
249 + defer node.StopDaemon()
250 +
251 + // Get all levels with 'all'
252 + res := node.IPFS("log", "level", "all")
253 + assert.NoError(t, res.Err)
254 +
255 + output := res.Stdout.String()
256 +
257 + // Should contain "(default): error" entry
258 + assert.Contains(t, output, "(default): error", "Should show default level with (default) key")
259 +
260 + // Should also contain various subsystems
261 + assert.Contains(t, output, "core: error")
262 + assert.Contains(t, output, "dht: error")
263 + })
264 +
265 + t.Run("'*' in get mode shows (default) entry", func(t *testing.T) {
266 + t.Parallel()
267 + node := harness.NewT(t).NewNode().Init().StartDaemon()
268 + defer node.StopDaemon()
269 +
270 + // Get all levels with '*'
271 + res := node.IPFS("log", "level", "*")
272 + assert.NoError(t, res.Err)
273 +
274 + output := res.Stdout.String()
275 +
276 + // Should contain "(default): error" entry
277 + assert.Contains(t, output, "(default): error", "Should show default level with (default) key")
278 +
279 + // Should also contain various subsystems
280 + assert.Contains(t, output, "core: error")
281 + assert.Contains(t, output, "dht: error")
282 + })
283 +
284 + t.Run("set all subsystems to 'default' using 'all' (alias for '*')", func(t *testing.T) {
285 + t.Parallel()
286 + node := harness.NewT(t).NewNode().Init().StartDaemon()
287 + defer node.StopDaemon()
288 +
289 + // Get the original default level (just for reference, it should be "error")
290 + res0 := node.IPFS("log", "level")
291 + assert.NoError(t, res0.Err)
292 + assert.Equal(t, "error", strings.TrimSpace(res0.Stdout.String()))
293 +
294 + // First set all subsystems to debug using 'all'
295 + res1 := node.IPFS("log", "level", "all", "debug")
296 + assert.NoError(t, res1.Err)
297 + assert.Contains(t, res1.Stdout.String(), "Changed log level of '*' to 'debug'")
298 +
299 + // Verify a specific subsystem is at debug
300 + res2 := node.IPFS("log", "level", "core")
301 + assert.NoError(t, res2.Err)
302 + assert.Equal(t, "debug", strings.TrimSpace(res2.Stdout.String()))
303 +
304 + // Verify the default level is now debug
305 + res3 := node.IPFS("log", "level")
306 + assert.NoError(t, res3.Err)
307 + assert.Equal(t, "debug", strings.TrimSpace(res3.Stdout.String()))
308 +
309 + // Now set all subsystems back to default (which is now "debug") using 'all'
310 + res4 := node.IPFS("log", "level", "all", "default")
311 + assert.NoError(t, res4.Err)
312 + assert.Contains(t, res4.Stdout.String(), "Changed log level of '*' to")
313 +
314 + // The subsystem should still be at debug (because that's what default is now)
315 + res5 := node.IPFS("log", "level", "core")
316 + assert.NoError(t, res5.Err)
317 + assert.Equal(t, "debug", strings.TrimSpace(res5.Stdout.String()))
318 +
319 + // The behavior is correct: "default" uses the current default level,
320 + // which was changed to "debug" when we set "all" to "debug"
321 + })
322 +
323 + t.Run("set all subsystems to 'default' keyword", func(t *testing.T) {
324 + t.Parallel()
325 + node := harness.NewT(t).NewNode().Init().StartDaemon()
326 + defer node.StopDaemon()
327 +
328 + // Get the original default level (just for reference, it should be "error")
329 + res0 := node.IPFS("log", "level")
330 + assert.NoError(t, res0.Err)
331 + // originalDefault := strings.TrimSpace(res0.Stdout.String())
332 + assert.Equal(t, "error", strings.TrimSpace(res0.Stdout.String()))
333 +
334 + // First set all subsystems to debug
335 + res1 := node.IPFS("log", "level", "*", "debug")
336 + assert.NoError(t, res1.Err)
337 + assert.Contains(t, res1.Stdout.String(), "Changed log level of '*' to 'debug'")
338 +
339 + // Verify a specific subsystem is at debug
340 + res2 := node.IPFS("log", "level", "core")
341 + assert.NoError(t, res2.Err)
342 + assert.Equal(t, "debug", strings.TrimSpace(res2.Stdout.String()))
343 +
344 + // Verify the default level is now debug
345 + res3 := node.IPFS("log", "level")
346 + assert.NoError(t, res3.Err)
347 + assert.Equal(t, "debug", strings.TrimSpace(res3.Stdout.String()))
348 +
349 + // Now set all subsystems back to default (which is now "debug")
350 + res4 := node.IPFS("log", "level", "*", "default")
351 + assert.NoError(t, res4.Err)
352 + assert.Contains(t, res4.Stdout.String(), "Changed log level of '*' to")
353 +
354 + // The subsystem should still be at debug (because that's what default is now)
355 + res5 := node.IPFS("log", "level", "core")
356 + assert.NoError(t, res5.Err)
357 + assert.Equal(t, "debug", strings.TrimSpace(res5.Stdout.String()))
358 +
359 + // The behavior is correct: "default" uses the current default level,
360 + // which was changed to "debug" when we set "*" to "debug"
361 + })
362 +
363 + t.Run("shell escaping variants for '*' wildcard", func(t *testing.T) {
364 + t.Parallel()
365 + h := harness.NewT(t)
366 + node := h.NewNode().Init().StartDaemon()
367 + defer node.StopDaemon()
368 +
369 + // Test different shell escaping methods work for '*'
370 + // This tests the behavior documented in help text: '*' or "*" or \*
371 +
372 + // Test 1: Single quotes '*' (should work)
373 + cmd1 := fmt.Sprintf("IPFS_PATH='%s' %s --api='%s' log level '*' info",
374 + node.Dir, node.IPFSBin, node.APIAddr())
375 + res1 := h.Sh(cmd1)
376 + assert.NoError(t, res1.Err)
377 + assert.Contains(t, res1.Stdout.String(), "Changed log level of '*' to 'info'")
378 +
379 + // Test 2: Double quotes "*" (should work)
380 + cmd2 := fmt.Sprintf("IPFS_PATH='%s' %s --api='%s' log level \"*\" debug",
381 + node.Dir, node.IPFSBin, node.APIAddr())
382 + res2 := h.Sh(cmd2)
383 + assert.NoError(t, res2.Err)
384 + assert.Contains(t, res2.Stdout.String(), "Changed log level of '*' to 'debug'")
385 +
386 + // Test 3: Backslash escape \* (should work)
387 + cmd3 := fmt.Sprintf("IPFS_PATH='%s' %s --api='%s' log level \\* warn",
388 + node.Dir, node.IPFSBin, node.APIAddr())
389 + res3 := h.Sh(cmd3)
390 + assert.NoError(t, res3.Err)
391 + assert.Contains(t, res3.Stdout.String(), "Changed log level of '*' to 'warn'")
392 +
393 + // Test 4: Verify the final state - should show 'warn' as default
394 + res4 := node.IPFS("log", "level")
395 + assert.NoError(t, res4.Err)
396 + assert.Equal(t, "warn", strings.TrimSpace(res4.Stdout.String()))
397 +
398 + // Test 5: Get all levels using escaped '*' to verify it shows all subsystems
399 + cmd5 := fmt.Sprintf("IPFS_PATH='%s' %s --api='%s' log level \\*",
400 + node.Dir, node.IPFSBin, node.APIAddr())
401 + res5 := h.Sh(cmd5)
402 + assert.NoError(t, res5.Err)
403 + output := res5.Stdout.String()
404 + assert.Contains(t, output, "(default): warn", "Should show updated default level")
405 + assert.Contains(t, output, "core: warn", "Should show core subsystem at warn level")
406 + })
407 + })
408 +
409 + t.Run("HTTP RPC", func(t *testing.T) {
410 + t.Run("get default level returns JSON", func(t *testing.T) {
411 + t.Parallel()
412 + node := harness.NewT(t).NewNode().Init().StartDaemon()
413 + defer node.StopDaemon()
414 +
415 + // Make HTTP request to get default log level
416 + resp, err := http.Post(node.APIURL()+"/api/v0/log/level", "", nil)
417 + require.NoError(t, err)
418 + defer resp.Body.Close()
419 +
420 + // Parse JSON response
421 + var result map[string]interface{}
422 + err = json.NewDecoder(resp.Body).Decode(&result)
423 + require.NoError(t, err)
424 +
425 + // Check that we have the Levels field
426 + levels, ok := result["Levels"].(map[string]interface{})
427 + require.True(t, ok, "Response should have 'Levels' field")
428 +
429 + // Should have exactly one entry for the default level
430 + assert.Equal(t, 1, len(levels))
431 +
432 + // The default level should be present
433 + defaultLevel, ok := levels[""]
434 + require.True(t, ok, "Should have empty string key for default level")
435 + assert.Equal(t, "error", defaultLevel, "Default level should be 'error'")
436 + })
437 +
438 + t.Run("get all levels using 'all' returns JSON (alias for '*')", func(t *testing.T) {
439 + t.Parallel()
440 + node := harness.NewT(t).NewNode().Init().StartDaemon()
441 + defer node.StopDaemon()
442 +
443 + expectedSubsystems := getExpectedSubsystems(t, node)
444 +
445 + // Make HTTP request to get all log levels using 'all'
446 + resp, err := http.Post(node.APIURL()+"/api/v0/log/level?arg=all", "", nil)
447 + require.NoError(t, err)
448 + defer resp.Body.Close()
449 +
450 + levels := parseHTTPResponse(t, resp)
451 + validateAllSubsystemsPresent(t, expectedSubsystems, levels, "JSON response")
452 +
453 + // Should have the (default) entry
454 + defaultLevel, ok := levels["(default)"]
455 + require.True(t, ok, "Should have '(default)' key")
456 + assert.Equal(t, "error", defaultLevel, "Default level should be 'error'")
457 + })
458 +
459 + t.Run("get all levels returns JSON", func(t *testing.T) {
460 + t.Parallel()
461 + node := harness.NewT(t).NewNode().Init().StartDaemon()
462 + defer node.StopDaemon()
463 +
464 + expectedSubsystems := getExpectedSubsystems(t, node)
465 +
466 + // Make HTTP request to get all log levels
467 + resp, err := http.Post(node.APIURL()+"/api/v0/log/level?arg=*", "", nil)
468 + require.NoError(t, err)
469 + defer resp.Body.Close()
470 +
471 + levels := parseHTTPResponse(t, resp)
472 + validateAllSubsystemsPresent(t, expectedSubsystems, levels, "JSON response")
473 +
474 + // Should have the (default) entry
475 + defaultLevel, ok := levels["(default)"]
476 + require.True(t, ok, "Should have '(default)' key")
477 + assert.Equal(t, "error", defaultLevel, "Default level should be 'error'")
478 + })
479 +
480 + t.Run("get specific subsystem level returns JSON", func(t *testing.T) {
481 + t.Parallel()
482 + node := harness.NewT(t).NewNode().Init().StartDaemon()
483 + defer node.StopDaemon()
484 +
485 + // First set a specific level for a subsystem
486 + resp, err := http.Post(node.APIURL()+"/api/v0/log/level?arg=core&arg=debug", "", nil)
487 + require.NoError(t, err)
488 + resp.Body.Close()
489 +
490 + // Now get the level for that subsystem
491 + resp, err = http.Post(node.APIURL()+"/api/v0/log/level?arg=core", "", nil)
492 + require.NoError(t, err)
493 + defer resp.Body.Close()
494 +
495 + // Parse JSON response
496 + var result map[string]interface{}
497 + err = json.NewDecoder(resp.Body).Decode(&result)
498 + require.NoError(t, err)
499 +
500 + // Check that we have the Levels field
501 + levels, ok := result["Levels"].(map[string]interface{})
502 + require.True(t, ok, "Response should have 'Levels' field")
503 +
504 + // Should have exactly one entry
505 + assert.Equal(t, 1, len(levels))
506 +
507 + // Check the level for 'core' subsystem
508 + coreLevel, ok := levels["core"]
509 + require.True(t, ok, "Should have 'core' key")
510 + assert.Equal(t, "debug", coreLevel, "Core level should be 'debug'")
511 + })
512 +
513 + t.Run("set level using 'all' returns JSON message (alias for '*')", func(t *testing.T) {
514 + t.Parallel()
515 + node := harness.NewT(t).NewNode().Init().StartDaemon()
516 + defer node.StopDaemon()
517 +
518 + // Set a log level using 'all'
519 + resp, err := http.Post(node.APIURL()+"/api/v0/log/level?arg=all&arg=info", "", nil)
520 + require.NoError(t, err)
521 + defer resp.Body.Close()
522 +
523 + // Parse JSON response
524 + var result map[string]interface{}
525 + err = json.NewDecoder(resp.Body).Decode(&result)
526 + require.NoError(t, err)
527 +
528 + // Check that we have the Message field
529 + message, ok := result["Message"].(string)
530 + require.True(t, ok, "Response should have 'Message' field")
531 +
532 + // Check the message content (should show '*' in message even when 'all' was used)
533 + assert.Contains(t, message, "Changed log level of '*' to 'info'")
534 + })
535 +
536 + t.Run("set level returns JSON message", func(t *testing.T) {
537 + t.Parallel()
538 + node := harness.NewT(t).NewNode().Init().StartDaemon()
539 + defer node.StopDaemon()
540 +
541 + // Set a log level
542 + resp, err := http.Post(node.APIURL()+"/api/v0/log/level?arg=core&arg=info", "", nil)
543 + require.NoError(t, err)
544 + defer resp.Body.Close()
545 +
546 + // Parse JSON response
547 + var result map[string]interface{}
548 + err = json.NewDecoder(resp.Body).Decode(&result)
549 + require.NoError(t, err)
550 +
551 + // Check that we have the Message field
552 + message, ok := result["Message"].(string)
553 + require.True(t, ok, "Response should have 'Message' field")
554 +
555 + // Check the message content
556 + assert.Contains(t, message, "Changed log level of 'core' to 'info'")
557 + })
558 +
559 + t.Run("set level to 'default' keyword", func(t *testing.T) {
560 + t.Parallel()
561 + node := harness.NewT(t).NewNode().Init().StartDaemon()
562 + defer node.StopDaemon()
563 +
564 + // First set a subsystem to debug
565 + resp, err := http.Post(node.APIURL()+"/api/v0/log/level?arg=core&arg=debug", "", nil)
566 + require.NoError(t, err)
567 + resp.Body.Close()
568 +
569 + // Now set it back to default
570 + resp, err = http.Post(node.APIURL()+"/api/v0/log/level?arg=core&arg=default", "", nil)
571 + require.NoError(t, err)
572 + defer resp.Body.Close()
573 +
574 + // Parse JSON response
575 + var result map[string]interface{}
576 + err = json.NewDecoder(resp.Body).Decode(&result)
577 + require.NoError(t, err)
578 +
579 + // Check that we have the Message field
580 + message, ok := result["Message"].(string)
581 + require.True(t, ok, "Response should have 'Message' field")
582 +
583 + // The message should indicate the change
584 + assert.True(t, strings.Contains(message, "Changed log level of 'core' to"),
585 + "Message should indicate level change")
586 +
587 + // Verify the level is back to error (default)
588 + resp, err = http.Post(node.APIURL()+"/api/v0/log/level?arg=core", "", nil)
589 + require.NoError(t, err)
590 + defer resp.Body.Close()
591 +
592 + var getResult map[string]interface{}
593 + err = json.NewDecoder(resp.Body).Decode(&getResult)
594 + require.NoError(t, err)
595 +
596 + levels, _ := getResult["Levels"].(map[string]interface{})
597 + coreLevel, _ := levels["core"].(string)
598 + assert.Equal(t, "error", coreLevel, "Core level should be back to 'error' (default)")
599 + })
600 + })
601 +
602 +}
603 +
604 +func getExpectedSubsystems(t *testing.T, node *harness.Node) []string {
605 + t.Helper()
606 + lsRes := node.IPFS("log", "ls")
607 + require.NoError(t, lsRes.Err)
608 + expectedSubsystems := SplitLines(lsRes.Stdout.String())
609 + assert.Greater(t, len(expectedSubsystems), 10, "Should have many subsystems")
610 + return expectedSubsystems
611 +}
612 +
613 +func parseCLIOutput(t *testing.T, output string) map[string]string {
614 + t.Helper()
615 + lines := SplitLines(output)
616 + actualSubsystems := make(map[string]string)
617 + for _, line := range lines {
618 + if strings.TrimSpace(line) == "" {
619 + continue
620 + }
621 + parts := strings.Split(line, ": ")
622 + assert.Equal(t, 2, len(parts), "Line should have format 'subsystem: level', got: %s", line)
623 + assert.NotEmpty(t, parts[0], "Subsystem should not be empty")
624 + assert.NotEmpty(t, parts[1], "Level should not be empty")
625 + actualSubsystems[parts[0]] = parts[1]
626 + }
627 + return actualSubsystems
628 +}
629 +
630 +func parseHTTPResponse(t *testing.T, resp *http.Response) map[string]interface{} {
631 + t.Helper()
632 + var result map[string]interface{}
633 + err := json.NewDecoder(resp.Body).Decode(&result)
634 + require.NoError(t, err)
635 + levels, ok := result["Levels"].(map[string]interface{})
636 + require.True(t, ok, "Response should have 'Levels' field")
637 + assert.Greater(t, len(levels), 10, "Should have many subsystems")
638 + return levels
639 +}
640 +
641 +func validateAllSubsystemsPresent(t *testing.T, expectedSubsystems []string, actualLevels map[string]interface{}, context string) {
642 + t.Helper()
643 + for _, expectedSub := range expectedSubsystems {
644 + expectedSub = strings.TrimSpace(expectedSub)
645 + if expectedSub == "" {
646 + continue
647 + }
648 + _, found := actualLevels[expectedSub]
649 + assert.True(t, found, "Expected subsystem '%s' should be present in %s", expectedSub, context)
650 + }
651 +}
652 +
653 +func validateAllSubsystemsPresentCLI(t *testing.T, expectedSubsystems []string, actualLevels map[string]string, context string) {
654 + t.Helper()
655 + for _, expectedSub := range expectedSubsystems {
656 + expectedSub = strings.TrimSpace(expectedSub)
657 + if expectedSub == "" {
658 + continue
659 + }
660 + _, found := actualLevels[expectedSub]
661 + assert.True(t, found, "Expected subsystem '%s' should be present in %s", expectedSub, context)
662 + }
663 +}
test/dependencies/go.mod
+1 -1
@@ -8,7 +8,7 @@ require (
8 github.com/Kubuxu/gocovmerge v0.0.0-20161216165753-7ecaa51963cd
9 github.com/golangci/golangci-lint v1.60.2
10 github.com/ipfs/go-cidutil v0.1.0
11 - github.com/ipfs/go-log/v2 v2.6.0
11 + github.com/ipfs/go-log/v2 v2.8.0
12 github.com/ipfs/go-test v0.2.2
13 github.com/ipfs/hang-fds v0.1.0
14 github.com/ipfs/iptb v1.4.1
test/dependencies/go.sum
+2 -2
@@ -343,8 +343,8 @@ github.com/ipfs/go-ipld-format v0.6.2 h1:bPZQ+A05ol0b3lsJSl0bLvwbuQ+HQbSsdGTy4xt
343 github.com/ipfs/go-ipld-format v0.6.2/go.mod h1:nni2xFdHKx5lxvXJ6brt/pndtGxKAE+FPR1rg4jTkyk=
344 github.com/ipfs/go-ipld-legacy v0.2.2 h1:DThbqCPVLpWBcGtU23KDLiY2YRZZnTkXQyfz8aOfBkQ=
345 github.com/ipfs/go-ipld-legacy v0.2.2/go.mod h1:hhkj+b3kG9b2BcUNw8IFYAsfeNo8E3U7eYlWeAOPyDU=
346 -github.com/ipfs/go-log/v2 v2.6.0 h1:2Nu1KKQQ2ayonKp4MPo6pXCjqw1ULc9iohRqWV5EYqg=
347 -github.com/ipfs/go-log/v2 v2.6.0/go.mod h1:p+Efr3qaY5YXpx9TX7MoLCSEZX5boSWj9wh86P5HJa8=
346 +github.com/ipfs/go-log/v2 v2.8.0 h1:SptNTPJQV3s5EF4FdrTu/yVdOKfGbDgn1EBZx4til2o=
347 +github.com/ipfs/go-log/v2 v2.8.0/go.mod h1:2LEEhdv8BGubPeSFTyzbqhCqrwqxCbuTNTLWqgNAipo=
348 github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU=
349 github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY=
350 github.com/ipfs/go-peertaskqueue v0.8.2 h1:PaHFRaVFdxQk1Qo3OKiHPYjmmusQy7gKQUaL8JDszAU=