CheckErr(err) function crashing in golang - go

If I run this code everything works fine and nothing is apparently wrong in the end result (the right id is being printed).
stmt, err := db.Conn.Prepare("INSERT INTO tablename a VALUES (?)")
CheckErr(err)
defer stmt.Close()
res, err := stmt.Exec(&t.Id)
CheckErr(err)
id, err := res.LastInsertId()
fmt.Println(id)
But when I add another CheckErr(err) at the end and I run, I get this:
runtime error: invalid memory address or nil pointer dereference
This is the first thing in the stack trace after the panics:
id, err := res.LastInsertId()
And no id is printed, which is weird since the println comes before the new CheckErr(err)
Any idea why this is happening? I'm clueless
func CheckErr(err error) {
if err != nil {
raven.CaptureErrorAndWait(err, nil)
}
}

CheckErr(err) does not exit or return if err != nil. The program will continue to execute to id, err := res.LastInsertId() and panic if res is nil.

Related

How can I assign a return value to a function input via short variable declaration in Golang?

Consider following code snippet...
f, err := os.OpenFile(".", os.O_RDONLY, 0666)
In-order to check for error & proceed, we need to have something like..
func checkerr(err error) {
if err != nil {
panic(err)
}
}
and then call this tiny function to validate the error. For eg..
f, err := os.OpenFile(".", os.O_RDONLY, 0666)
checkerr(err)
files, err := f.Readdirnames(0)
checkerr(err)
While this works, I'm looking for a shortcut to directly call checkerr() during initialisation phase itself. See below...
f, checkerr(err) := os.OpenFile(".", os.O_RDONLY, 0666)
Is it possible using native Golang constructs?
Repeat after me: "It's idiomatic Go to check for errors." The following is not bad code, even if it's not the DRYest.
f, err := os.OpenFile(".", os.O_RDONLY, 0666)
if err != nil {
panic(err)
}
files, err := f.Readdirnames(0)
if err != nil {
panic(err)
}

How to pass (type *common.MapStr) to type []byte?

Sorry if the question is too newbie, as i just started to learn go yesterday.
I try to convert publishEvent into bytes, and compiler shown error like following:
cannot convert publishEvent (type *common.MapStr) to type []byte
Can anyone show me the way ?
Thank You.
var parsed map[string]interface{}
bytes := []byte(publishEvent) --->Error occur here
err := json.Unmarshal(bytes, &parsed)
if err != nil{
fmt.Println("error: ", err)
}
I assume the struct you are working with is common.MapStr from https://github.com/elastic/libbeat
common.MapStr is already a map[string]interface{} so I'm not sure why you are turing it into JSON, and then parsing it back into the same kind of structure, but if thats what you really want to do, replacing the error line with:
bytes, err := json.Marshal(publishEvent)
should work. You will get an error on the next line about redeclaring err so change it to:
err = json.Unmarshal(bytes, &parsed)
Resulting in the following code (also added another error check):
var parsed map[string]interface{}
bytes, err := json.Marshal(publishEvent)
if err != nil{
fmt.Println("error: ", err)
// you'll want to exit or return here since we can't parse `bytes`
}
err = json.Unmarshal(bytes, &parsed)
if err != nil{
fmt.Println("error: ", err)
}

Push data from Golang to OpenTSTB

I have stored the last one hour data into file. So I've to upload the previous data to openTSTB.
So, the code is as follows:
go func() {
file, err := os.Open("/var/lib/agent/agent.db")
if err != nil {
fmt.Println(err, "Err")
}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
arr := []byte(scanner.Text())
url := "http://192.168.2.40:4242/api/put"
req, err := http.NewRequest("POST", url, bytes.NewBuffer(arr))
req.Header.Set("Content-Type", "")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
}()
The above code pushes the last one hour data to openTSTB.
Current data is also pushed to openTSTB using another GoRoutine.
The code is as follows:
// Regular run
go func() {
timeStamp, _ := strconv.ParseInt(strconv.FormatInt(time.Now().UnixNano()/1e9, 10), 10, 64)
err := opentsdb.Put(
MetricName,
4,
timeStamp,
opentsdb.Tag{"host", hostname},
)
}()
The problem is if last record is 4, my previous record has been uploaded with the old data [Ex: 4+4].
If I run single GoRoutine, it is working correctly. If I go with old and current data, the result is wrong.
How to fix this? Any help is greatly appreciated. Thanks in advance.

Go: error variable reassigning, proper use?

I'm confusing about the reassignment of the err variable for errors in Go.
For example, I tend to be doing this:
err1 := Something()
checkErr(err1)
str, err2 := SomethingElse()
checkErr(err2)
err3 := SomethingAgain()
checkErr(err3)
But I'm always losing track of this and have millions of useless err variables floating around that I don't need, and it makes the code messy and confusing.
But then if I do this:
err := Something()
checkErr(err)
str, err := SomethingElse()
checkErr(err)
err := SomethingAgain()
checkErr(err)
...it gets angry and says err is already assigned.
But if I do this:
var err error
err = Something()
checkErr(err)
str, err = SomethingElse()
checkErr(err)
err = SomethingAgain()
checkErr(err)
...it doesn't work because str needs to be assigned with :=
Am I missing something?
you're almost there... at the left side of := there needs to be at least one newly create variable. But if you don't declare err in advance, the compiler tries to create it on each instance of :=, which is why you get the first error. so this would work, for example:
package main
import "fmt"
func foo() (string, error) {
return "Bar", nil
}
func main() {
var err error
s1, err := foo()
s2, err := foo()
fmt.Println(s1,s2,err)
}
or in your case:
//we declare it first
var err error
//this is a normal assignment
err = Something()
checkErr(err)
// here, the compiler knows that only str is a newly declared variable
str, err := SomethingElse()
checkErr(err)
// and again...
err = SomethingAgain()
checkErr(err)

When should you initialize a new variable and when you should not?

I'm looking at the code examples sql.query and i'm a bit confused by the way the variables are initialized. As far as I understand the var keyword initialize the variable but if you already have a such variable it's better to 'reuse' it instead to reinitialize it. I'm aware that I might have misunderstood the golang specs so I hope this question would help me (and perhaps other folks) get it right.
rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
log.Fatal(err)
}
fmt.Printf("%s is %d\n", name, age)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
Why is the "name" variable initialized within the loop and not outside the loop ? (see below). Isn't it less performant to reinitialize it on each loop ?
//how I would do this
rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var name string //outside the loop
for rows.Next() {
if err := rows.Scan(&name); err != nil {
log.Fatal(err)
}
fmt.Printf("%s is %d\n", name, age)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
or even better use a pointer
rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
name := new(string) //pointer outside the loop
for rows.Next() {
if err := rows.Scan(name); err != nil {
log.Fatal(err)
}
fmt.Printf("%s is %d\n", name, age)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
Unless you have determined that the allocation is a performance bottleneck, I wouldn't consider such a premature optimisation. After all, it might not even make a difference, so it is best to err on the side of readability/maintainability.
In general, I'd suggest using the smallest scope for your variables that makes sense. If they are stack allocated, then they will be quite cheap -- assuming space is available, it probably just involves initialising the variable to zero or its initial value. Stack allocated variables scoped within a loop will probably end up with the same memory location each time through the loop too, so there isn't much to be gained from moving them out.
With that said, it isn't always obvious when a variable will be allocated on the stack. If the compiler decides that the pointer passed to row.Scan could possibly be retained past the function call (that is, it escapes), then name will be allocated on the heap even though it has been defined with var.
Similarly if the escape analysis determines that the variable doesn't escape, the version that creates the string variable with new may decide to place it on the stack.

Resources