dialAlpha
dialAlpha

Reputation: 443

Golang: fmt, variadic args and %!(EXTRA type=value) error

I'm implementing a wrapper around the standard log package to make a logger with various log levels.

I have the following interface:

type Logger interface {
  Trace(fmt string, args ...interface{})
  Debug(fmt string, args ...interface{})
  Info(fmt string, args ...interface{})
  Warn(fmt string, args ...interface{})
  Error(fmt string, args ...interface{})
  Fatal(fmt string, args ...interface{})
  Panic(fmt string, args ...interface{})
}

In the implementation I have something like this (not the exact code)

func Info(format string, args ...interface{}){
  msg := fmt.Sprintf(format, args...)
  log.Println(msg)
}

Now, assume I call my library like this:

logger.Info("Hello %s", "World")

I get the printout: "Hello %!(EXTRA string=WORLD)", instead of the expected "Hello World". There a similar output if I do

msg := fmt.Sprintf(format, args)

This returns "Hello World%!EXTRA []interface{}=[]".

Upvotes: 16

Views: 27717

Answers (5)

tpa
tpa

Reputation: 1

Also, happens due to a simple (typo?) if you forget/miss putting in the "%". e.g.

fmt.Printf("v\n", myvar) 

instead of

fmt.Printf("%v\n", myvar)

obviously not a "syntax" error, so nothing for the compiler to catch. I realize this nets out to the same as some of the other answers, but I think this is clearer and (maybe?) the most common cause.

Upvotes: 0

ori888
ori888

Reputation: 750

This can happen if you pass nil params to your format, for instance:

myStr := fmt.Sprintf("check/%s", "hello", nil)

will set the value of myStr to: "check/hello%!" In this example the extra params was the third param with nil value.

so make sure to remove any extra params.

Upvotes: 0

NotX
NotX

Reputation: 2415

Happens aswell when your message has no verbs and the varargs are empty but coming from elsewhere:

func CustomPrintf(message string, a ...interface{}) {
    fmt.Printf(message, a) // for no verbs in message you'll get this "EXTRA" suffix
}

That's a special case of a general error. You've got to spread a first. So use fmt.Printf(message, a...) to make it to varags again.

Upvotes: 0

dialAlpha
dialAlpha

Reputation: 443

The error was between the chair and keyboard. I mixed up the following interfaces:

func Print(v ...interface{})
func Printf(format string, v ...interface{})

Some of my code was calling the library without a format string.See here for a more detailed example: http://play.golang.org/p/Xx79qujaFp

Upvotes: 10

BoppreH
BoppreH

Reputation: 10193

I can't reproduce this behavior. Are you sure it's not a simple error that you forgot to show here?

https://play.golang.org/p/-jtmll17Xj

package main

import "fmt"

func Info(format string, args ...interface{}){
    msg := fmt.Sprintf(format, args...)
    fmt.Print(msg)
}

func main() {
    Info("Hello %s", "World")
}

Prints

Hello World

According to the fmt docs, %!(EXTRA string=WORLD) is added to the string when you pass extra parameters, unexpected by the format. Maybe you are using the format string "Hello World" instead of "Hello %s", or passing the argument twice?

Upvotes: 21

Related Questions