I get a strange error while building my go project.
My structure:
-$GOPATH
-src
-main
-main.go
-configuration
-configuration.go
configuration.go:
package configuration;
type Config int;
func (c Config) Parse(s string) map[string]string {...}
main.go
package main;
import"configuration"
func main() {
var config Config;
argMap := config.parse(...);
return;
}
if my working directory is $GOPATH, I do:
go build configuration - no output, OK
go build main
imported and not used "configuration"
undefined: Config
So my package is found ($GOPATH/pkg contains configuration.go with correct content - I can see the Parse method) and main imports it, but does not recognize its contents?
I recon the problem is that the type Config is not exported? Why would that be?
You are trying to use Config from package main, where it is not defined, instead of the one from configuration (thats the error "imported and not used"):
package main
import "configuration"
func main() {
var config configuration.Config
argMap := config.Parse(...)
}
The second problem is calling unexported parse instead of Parse as explained by VonC.
argMap := config.parse(...); wouldn't work, since you declared a Parse() method.
(as in "exported method configuration.Parse()")
var config configuration.Config
argMap := config.Parse(...);
Config is exported, but the methods are case-sensitive (cf. Exported Identifiers).
Related
I'm new to Go and I've created an application which is working as expected.
My application structure is like following:
myproj
Gopkg.toml
Gopkg.lock
src
server
main.go
utils
file1.go
logger.go
handler
handler1.go
handler2.go
Now inside the main.go file I've created a logger like the following:
File server-> main.go
import (
"handler"
"utils"
"github.com/sirupsen/logrus"
)
var logger *logrus.Logger
fun init(){
logger = utils.InitLogs()
}
func main(){
logger.info("my message")
…
handler.run()
}
Everything is working as expected!
Now I want to use the logger inside the handler1&2 files (from diff package inside my local project)
To do this, I did the following steps.
Inside the handler init the logger (exactly as I did in the main file) and it’s working
File handler-> handler1.go
import (
"utils"
"github.com/sirupsen/logrus"
)
var logger *logrus.Logger
fun init(){
//Init the logger again
logger = utils.InitLogs()
}
func run(){
//here Im not using logger otherwise maybe I can move it as parameter…
}
func build(){
//Here Im using the logger
logger.info("Hi")
}
While this is working but I've created two instance of logger, first on main and second on handler1 which Im not sure is best
My questions are:
I want to reuse the logger inside the handler class/module, is a better way to do it in Go?
This is diff package (inside my local proj) and I'm not sure that I'm that if Im not re-use the same logger object from the main method, this is the right way to do it...
(lower prio question) Is my project structure okay for Go? I used this as reference which is similar...also this which is a bit different
If you want to share your logger instance across your project, one way is to just export it as a global variable from your utils package as Armin suggested in his answer:
package utils
...
var Logger *logrus.Logger
func init() {
Logger = InitLogs()
}
I'd bet you can then get away with not having to export InitLogs() by changing it to initLogs()
Then, elsewhere in your code, you can import utils and use that logger instance:
import "utils"
...
func something() {
utils.Logger.Info("Hi")
}
Alternatively, if it makes sense to keep all your configuration in one place, you can declare your logger pointer as a field of a config struct and initialize it along with the rest of your program configuration (if you have any).
For example, say you have the following in your utils package:
package utils
...
type MyAppConfig struct {
// whatever config parameters your app needs,
// like DB connections, etc.
Logger *logrus.Logger
}
// pass in whatever configuration parameters you need,
// like DB URL, etc.
func InitConfig() (*MyAppConfig, error) {
// set up other configuration
config := &MyAppConfig{
// other config
Logger: InitLogs(),
}
return config, nil
}
func (c *MyAppConfig) DoSomethingImportant() {
c.Logger.Info("Hello")
}
Meanwhile, you can use this anywhere else, like in your CLI interface:
package main
import "utils"
...
func main() {
// input, or CLI parameters...
// pass in other CLI parameters, if any
// (of course you'd have to change the function signature in
// the previous file above)
config, err := utils.NewConfig()
if err != nil {
// handle error
}
config.DoSomethingImportant()
// or since Logger is exported:
config.Logger.Info("hello")
}
If you find you end up with lots of global things like the Logger you need to configure, the config struct is the more scalable approach IMO. As an added bonus, using a config type makes it easier to do dependency injection in unit tests than having the global variables used directly.
On the other hand, if you only have to worry about the one global Logger, then the config struct might be overkill, especially if it's not something you'll need to instrument when designing tests. It's a subjective call depending on your circumstances.
To answer your second question...
Project Layout
If /server has a main package with a command, move it under cmd/server.
Also, the way you currently have it, it would be a bit confusing for others to depend on your project. Since your repository appears to begin at src/, here's what it will look like when someone else tries to import your utils package:
File structure:
<top of someone else's GOPATH>/
src/
myproject/src/utils/
...
To import:
import "myproject/src/utils"
... and actually, since you import "utils" in your code right now, I don't think your code will compile in someone else's GOPATH because they don't have a $GOPATH/src/utils.
Solution: Your repository should not include src/. The idea is that you setup your $GOPATH and you put different repositories/packages inside of it. For example (assuming you host your code on Github):
<top of gopath>/
src/
github.com/you/myproject/ <---- your repo starts here
cmd/server/
main.go
utils
file1.go
logger.go
handler
handler1.go
handler2.go
This would make your packages importable to you and to others like so:
import "github.com/you/myproject/utils"
Also, this project structure allow others to include your project inside their $GOPATH or in their vendor/ interchangeably.
It seems you want to use the exact logger from main.go. You should just export it and use it in other packages:
server/main.go
var Logger *logrus.Logger // Notice capital L
func main() {
Logger = utils.InitLogs() // Init logger once
...
}
handler/handler1.go
import "server"
func run(){
//here Im not using logger otherwise maybe I can move it as parameter…
}
func build(){
// No need to initialize logger as its done in main func.
//Here Im using the logger
server.Logger.info("in xyz")
}
And your project structure is not standard. See this.
I've read the doc on creating custom packages, etc but I can't seem to pin down what the problem is.
GOPATH=/Users/lrsmith/GoWorkSpace
|->bin
|->pkg
|->src
|->github.com
|->lrsmith
|-> zaphod
|-> zaphod.go
I've done a 'go get github.com/lrsmith/go-icinga2-api/iapi' and it
dropped it into the same dir as 'zaphod' and created and .a file under pkg.
GOPATH=/Users/lrsmith/GoWorkSpace
|->bin/
|->pkg/
|->..../iapi.a
|->src/
|->github.com/
|->lrsmith/
|-> zaphod/
|-> zaphod.go
|-> go-icinga2-api/
zaphod.go is very simple right now
package main
import (
"github.com/lrsmith/go-icinga2-api/iapi"
)
func main () {
t := iapi.Config("zaphod","beeblebrox","http://localhost",true)
}
When I do a go build in the zaphod directory I get
./zaphod.go:11: undefined: iapi.Config
I've read through the docs, checked cases and tried different structures but I can't seem to get it to load the package and let me call iapi.Config. The iapi code works and if I build something in the go-icinga2-api directory it works fine and the test all pass.
I want to create a separate project/code base that imports the go-icinga2-api and uses it, but can't seem to get it work.
Thanks
Len
Added info. The structure for go-icinga2-api is
go-icinga2-api
|-> iapi
|-> client.go
|-> client_test.go
|-> host.go
.......
client.go is
// Package iapi provides a client for interacting with an Icinga2 Server
package iapi
import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"net/http"
)
// Server ... Use to be ClientConfig
type Server struct {
Username string
Password string
BaseURL string
AllowUnverifiedSSL bool
httpClient *http.Client
}
// func Config ...
func (server *Server) Config(username, password, url string, allowUnverifiedSSL bool) (*Server, error) {
// TODO : Add code to verify parameters
return &Server{username, password, url, allowUnverifiedSSL, nil}, nil
}
I've tried with the .go files up one level, i.e. not nested underneath iapi/ to for the same results.
Updated Answer
In client.go, it looks like you're trying to use Config as a constructor for Server structs. Since Config is defined with a receiver (func (server *Server)), it's a method of Server and can't be called directly. You're code should work if you remove (server *Server).
It's idiomatic to name constructors New[type being returned], or New if the type is the same name as the package.
From the 3rd paragraph of the Package Names section of Idiomatic Go:
the function to make new instances of ring.Ring—which is the definition of a constructor in Go—would normally be called NewRing, but since Ring is the only type exported by the package, and since the package is called ring, it's called just New, which clients of the package see as ring.New
Original Answer
The import path should reference a directory. In your code, you then reference that package by whatever name is used in the package [name] in the .go files in that directory.
For example, if github.com/lrsmith/go-icinga2-api contains a file called api.go with the line package iapi, your importing package should look like this:
package main
import (
"github.com/lrsmith/go-icinga2-api"
)
func main () {
t := iapi.Config("zaphod","beeblebrox","http://localhost",true)
}
Note the declaration of the Config() function:
func (server *Server) Config(username, password, url string, allowUnverifiedSSL bool) (*Server, error)
It's a "method" that should be applied to a Server object:
server.Config(...)
Thus you need to first create a Server object (or you could try with nil):
var server iapi.Server
server, err := server.Config(...)
You're trying to run it as if it had the following declaration:
func Config(username, password, url string, allowUnverifiedSSL bool) (*Server, error)
We parse flags in main.go which is in main package, of course. Then we have another package where we want to read some flag's value.
flags.Args() work fine, it will return all non-flag values.
But I cannot figure out to how read already parsed value for a flag in a package other than main.
Is it possible?
Thanks
Amer
I had the same requirement recently and I wanted a solution that avoided calling flag.Parse repeatedly in init functions.
Perusing the flag package I found Lookup(name string) which returns a Flag which has a Value. Every built in Value implements the flag.Getter interface. The call chain looks like this:
flag.Lookup("httplog").Value.(flag.Getter).Get().(bool)
If you mistype the flag name or use the wrong type you get a runtime error. I wrapped the lookup in a function that I call directly where needed since the lookup and get methods are fast and the function is not called often. So the main package declares the flag.
// main.go
package main
import "flag"
var httplog = flag.Bool("httplog", false, "Log every HTTP request and response.")
func main() {
flag.Parse()
// ...
}
And the utility package, which is decoupled from main except for the flag name, reads the flag value.
// httpdiag.go
package utility
import "flag"
func logging() bool {
return flag.Lookup("httplog").Value.(flag.Getter).Get().(bool)
}
You can define the var storing the flag in the separate package, as an exported variable, then call the flag parsing in the main package to use that variable, like this:
mypackage/const.go
var (
MyExportedVar string
)
mainpackage/main.go
func init() {
flag.StringVar(&mypackage.MyExportedVar, "flagName", "defaultValue", "usage")
flag.Parse()
}
This way, everybody can access that flag, including that package itself.
Note:
this only works for exported variables.
You can define the flag in that package and call flag.Parse() in func init(), flag.Parse can be called multiple times.
However, if you want to access the flag's value from multiple packages you have to expose it or create an exposed function to check it.
for example:
// pkgA
var A = flag.Bool("a", false, "why a?")
func init() {
flag.Parse()
}
// main package
func main() {
flag.Parse()
if *pkgA.A {
// stuff
}
}
Also you can use FlagSet.Parse(os.Args) if you want to reparse the args.
When you parse your flags, parse them into global variables which start with an initial Capital so they are public, eg
package main
var Species = flag.String("species", "gopher", "the species we are studying")
func main() {
flag.Parse()
}
Then in your other package you can refer to them as
package other
import "/path/to/package/main"
func Whatever() {
fmt.Println(main.Species)
}
I have a file called login.go and account.go
In login.go
func (api *ApiResource) test() {
fmt.Println("Works!")
}
In account.go I have:
func main () {
Res := new(ApiResource)
Res.test()
}
Buit I'm getting undefined:test error.
They both use package main and are on same src/ folder
What do I need to fix here?
If you used go run then you must pass both files to like go run login.go account.go.
I created following file structure in $GOPATH/src
bitbucket.org/MyName/ProjectName
I have follwoing files here
ProjectName
- controllers/
- meController.go
- app.go
In app.go I'm importing my controller like that:
import "bitbucket.org/MyName/ProjectName/controllers"
And in main func I'm trying to use it's method.
meController = new(controllers.meController)
m.Get("/", meController.Index)
My meController.go looks like this
package controllers
type meController struct {
}
func (controller *meController) Index () string {
return "Hello World"
}
But I'm getting this error:
./app.go:5: imported and not used: "bitbucket.org/MyName/ProjectName/controllers"
./app.go:12: undefined: meController
I don't have any idea how to get this to work.
Any ideas?
Thanks!
In Go, every symbol that starts with lowercase is not exported by the package. call your struct MeController and you'll be fine.