Send log to Rsyslog server with go - linux

I write a code to send log to rsyslog server on ubuntu, the code has below content. In the file ryslogd.conf I have configured local7.* /var/log/test.log.*But when running, the log is not written to the test.log
*
package main
import (
"errors"
"fmt"
"log/syslog"
"os"
"path/filepath"
)
func main() {
programName := filepath.Base(os.Args[0])
fmt.Println(programName)
syslog_pointer, err := syslog.Dial("udp", "localhost:514", syslog.LOG_WARNING|syslog.LOG_LOCAL7, "test")
if err != nil {
err_exception := errors.New("Can't connect to syslog server localhost:514")
fmt.Println(err_exception)
os.Exit(1)
} else {
syslog_pointer.Emerg("This is log test")
}
}
I want the log line: this is test log to be written to the file /var/log/test.log

Local logging is typically via a Unix socket. UDP logging typically needs to be explicitly enabled for the Syslog server.
Creating the syslog.Writer via syslog.New will attempt to connect via common Unix sockets first, then attempt UDP via localhost:
package main
import (
"log"
"log/syslog"
)
func main() {
s, err := syslog.New(syslog.LOG_WARNING|syslog.LOG_LOCAL7, "test")
if err != nil {
log.Fatal(err)
}
s.Emerg("log test")
}

Related

fork/exec ./node_modules/.bin/solcjs: no such file or directory

I have a small issue here when I try to run this code
package main
import (
"fmt"
"os/exec"
)
func main() {
out, err := exec.Command("./node_modules/.bin/solcjs", "--version").Output()
if err != nil {
panic(err)
}
fmt.Println(out)
}
This code will get solcjs version from ./node_modules/.bin/solcjs.
But, the code return an error telling me that the file/folder doesn't exist, and I try the command ./node_modules/.bin/solcjs --version my self and it work perfectly. Why when i use go it show error?
You probably need to mention the full path of the solcjs file.
Use snippet below to take the current working directory and then add this path before /node_modules/.bin/solcjs:
mydir, _ := os.Getwd()
file_full_path := mydir + "/node_modules/.bin/solcjs"
out, err := exec.Command(file_full_path, "--version").Output()

How to restart itself in Go daemon process?

I use go-daemon library to fork process and run it in background. And I need to restart the daemon process after update performed from within http handler.
The handler code is
func httpUpdate(w http.ResponseWriter, req *http.Request) {
if !isPost(req.Method) {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
if checkAuth(req) != 200 {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
}
log.Println("INFO: Update request, checking for update...")
var err = doUpdate(UPDATE_URL, nil, false)
if !isError(err) {
log.Println("INFO: Update successful, exit")
var system = RealSystem{}
system.Run(fmt.Sprintf("(sleep 0.3s && %s start &> /test/extra.log)&disown", appFilename()))
system.Exit(0)
return
}
w.WriteHeader(http.StatusNoContent)
}
doUpdate() returns nil if successfully replaced the executable file. RealSystem is just wrapper for exec.Command and os.Exit(). appFilename() is the executable file name. The command to start app is /path/to/app start.
I see that new process starts, but executing Context::Reborn() fails with EOF error. Looks like some intrinsic pipes used as implementation details fail with EOF (may be...).
What would be the reason? Or may be there is a better way of doing that?
For now everything happens inside docker container in the "context" of e2e test if it matters. I spent hours trying to make it work but with no success.
I assume you mean restarting the currently running Go binary. You can use a syscall for unix-based systems, and use an exec.Command for Windows.
func RestartSelf() error {
self, err := osext.Executable()
if err != nil {
return err
}
args := os.Args
env := os.Environ()
// Windows does not support exec syscall.
if runtime.GOOS == "windows" {
cmd := exec.Command(self, args[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
cmd.Env = env
err := cmd.Run()
if err == nil {
os.Exit(0)
}
return err
}
return syscall.Exec(self, args, env)
}
The issue is specific to the library. Spawn new self instance from within child process is not a problem for the system, but for that library.
To achieve this it's necessary to execute something like that.
Note the _GO_DAEMON=0 variable set to zero. This makes library follow parent control flow.
var cmd = exec.Command("bash", "-c", fmt.Sprintf("sleep 0.5s; _GO_DAEMON=0 %s start", appFilename()))
var err = cmd.Start()
Also it was necessary to make small changes to the original library. Here is the fork.

using curl with commands in go

I'm using Go with command to execute curl which works as expected
curl := exec.Command("curl", "https://services.odata.org/V3/northwind/northwind.svc/")
out, err := curl.Output()
if err != nil {
fmt.Println("erorr" , err)
return
}
fmt.Println(out)
Now I want to use some placeholders like
curl -O http://quiet-waters-1228.herokuapp.com/assets/image.jpg
but now I need to get the url for command
e.g. if I run in bash mytool url I got the url value
`curl -O $(mytool url)`
The problem is that we need to execute the command in the code and I'm not sure how to pass it
curl := exec.Command("curl", "curl -O $(url)")
out, err := curl.Output()
if err != nil {
fmt.Println("erorr" , err)
return
}
fmt.Println(out)
In os package you have slice of strings which contains all arguments passed by shell to your program.
os.Args 0th value, i.e., first element is going to be name of the command itself.
If your tool command is mytool, os.Args[0] contains mytool.
Rest are going to be the arguments, which are passed by shell.
package main
import (
"log"
"os"
"os/exec"
)
func main() {
if len(os.Args) < 2 {
// If argument is not provided quit
log.Fatalln("url not provided")
}
url := os.Args[1] // URL
cmd := exec.Command("curl", "-O", url)
cmd.Run()
}
You can also download multiple URLs concurrently,
var wg *sync.WaitGroup
func main() {
urls := os.Args[1:]
wg = new(sync.WaitGroup)
wg.Add(len(urls))
for _, url := range urls {
go download(url)
}
wg.Wait()
}
func download(url string) {
defer wg.Done()
cmd := exec.Command("curl", "-O", url)
cmd.Run()
}

Write on thermal printer device in golang

I have a thermal printer(ESC/POS) already configured on my linux machine and using the terminal command (as root) I can make it print:
echo "Hello!" > /dev/usb/lp0
However, doing the same procedure in golang nothing happens:
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Hello Would!")
f, err := os.Open("/dev/usb/lp0")
if err != nil {
panic(err)
}
defer f.Close()
f.Write([]byte("Hello world!"))
}
What am I doing wrong?
As described in the documentation os.Open() opens a file read-only.
You would have discovered the problem if you had checked the return from your Write() call. Always check errors. Don't ignore them, even in tiny programs like this; they will give you a clue as to what is wrong.
To fix the problem, open the device special for writing with os.OpenFile().
f, err := os.OpenFile("/dev/usb/lp0", os.O_RDWR, 0)

Trying to launch an external editor from within a Go program

I am trying to figure out how to launch an external editor from within a Go program, wait for the user to close the editor, and then continue execution of the program. Based on this SO answer, I currently have this code:
package main
import (
"log"
"os"
"os/exec"
)
func main() {
fpath := os.TempDir() + "/thetemporaryfile.txt"
f, err := os.Create(fpath)
if err != nil {
log.Printf("1")
log.Fatal(err)
}
f.Close()
cmd := exec.Command("vim", fpath)
err = cmd.Start()
if err != nil {
log.Printf("2")
log.Fatal(err)
}
err = cmd.Wait()
if err != nil {
log.Printf("Error while editing. Error: %v\n", err)
} else {
log.Printf("Successfully edited.")
}
}
When I run the program, I get this:
chris#DPC3:~/code/go/src/launcheditor$ go run launcheditor.go
2012/08/23 10:50:37 Error while editing. Error: exit status 1
chris#DPC3:~/code/go/src/launcheditor$
I have also tried using exec.Run() instead of exec.Start(), but that doesn't seem to work either (though it doesn't fail at the same place).
I can get it to work if I use Gvim instead of Vim, but it refuses to work with both Vim and nano. I think it's related to Vim and nano running inside the terminal emulator instead of creating an external window.
Apparently, you have to set Stdin, Stdout and Stderr on the Cmd object to os.Std(in|out|err). Like this (assuming that the object is called cmd):
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
Credit for solving this goes to the guys on #go-nuts on freenode.
This works for me but it has the disadvantage of opening another terminal (which will automatically close after edition) :
cmd := exec.Command("/usr/bin/xterm", "-e", "vim "+fpath)
Here in cmd := exec.Command("vim", fpath), you're doing more or less:
$ PATH= vim foo.txt
bash: vim: No such file or directory
$
Shell uses the PATH environment variable, exec.Command does not. You have to lookup the vim binary and pass its full path to exec.Command. exec.LookPath does that for you.

Resources