Skip to content
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

Channel close bugfix #85

Merged
merged 3 commits into from
Jul 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions channel/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,23 @@ func (c *Channel) Open() error {

// Close signals to stop the channel read loop and closes the underlying Transport object.
func (c *Channel) Close() error {
c.done <- true

return c.t.Close(false)
ch := make(chan struct{})

go func() {
c.done <- true

ch <- struct{}{}
}()

select {
case <-ch:
return c.t.Close(false)
case <-time.After(2 * (c.ReadDelay * c.ReadDelay)): // nolint: gomnd
// channel is stuck in a blocking read, force close transport to finish closing connection,
// so give it 2*(c.ReadDelay squared) to "nicely" exit -- with defaults this ends up being
// 50ms.
return c.t.Close(true)
}
}

type result struct {
Expand Down
7 changes: 7 additions & 0 deletions examples/generic_driver/custom_logging/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Custom Logging
===============

If you want to use a custom logging setup with one or more outputs you can create a `logging.
Instance` and pass it to the driver via the `WithLogger` option. The logging instance can accept
as many "loggers" as you want to give it -- these "loggers" can be any function that accepts a
variadic of interface. Check out the example to see this in action.
66 changes: 66 additions & 0 deletions examples/generic_driver/custom_logging/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package main

import (
"fmt"
"log"

"github.com/scrapli/scrapligo/logging"

"github.com/scrapli/scrapligo/driver/generic"
"github.com/scrapli/scrapligo/driver/options"
)

func myLoggerFunc(x ...interface{}) {
// not sure why you would want to do this, but this is just an example logger function you
// could use :)
if len(x) > 0 {
// pro tip... its almost certainly going to be a string, but this is just to show how
// you can add logger functions so who cares!
fmt.Printf("got a log item of type %T\n", x[0])
}
}

func main() {
li, err := logging.NewInstance(
logging.WithLevel(logging.Debug),
logging.WithLogger(log.Print),
logging.WithLogger(myLoggerFunc),
)
if err != nil {
fmt.Printf("failed to logging instance; error: %+v\n", err)

return
}

d, err := generic.NewDriver(
"sandbox-iosxe-latest-1.cisco.com",
options.WithAuthNoStrictKey(),
options.WithAuthUsername("developer"),
options.WithAuthPassword("C1sco12345"),
// the options.WithLogger applies the logging instance created above to our driver
options.WithLogger(li),
)
if err != nil {
fmt.Printf("failed to create driver; error: %+v\n", err)

return
}

err = d.Open()
if err != nil {
fmt.Printf("failed to open driver; error: %+v\n", err)

return
}

defer d.Close()

r, err := d.SendCommand("show version | i Version")
if err != nil {
fmt.Printf("failed to run command; error: %+v\n", err)

return
}

fmt.Printf("got some output: %s\n\n\n", r.Result)
}
15 changes: 14 additions & 1 deletion logging/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package logging

import (
"fmt"
"sync"

"github.com/scrapli/scrapligo/util"
)
Expand Down Expand Up @@ -42,9 +43,21 @@ type Instance struct {

// Emit "emits" a logging message m to all the loggers in the Instance.
func (i *Instance) Emit(m interface{}) {
wg := sync.WaitGroup{}

for _, f := range i.Loggers {
f(m)
wg.Add(1)

lf := f

go func() {
lf(m)

wg.Done()
}()
}

wg.Wait()
}

func (i *Instance) shouldLog(l string) bool {
Expand Down