Documentation
¶
Overview ¶
GOP (GOlang-in-Production) is a collection of code intended to ease writing production-safe golang applications, particularly web applications.
Providing configuration ¶
GOP expects you to create an ini-formatted configuration file for your application. It will attempt to load it during the call gop.Init(), and will raise an error if it cannot find it.
Here is how GOP determines the location of the configuration file:
If you set the environment variable called $PROJECT_$APP_CFG_FILE (all uppercase), where $PROJECT and $APP are the projectName and appName parameters that you have passed to gop.Init() as arguments, GOP will check that location for the configuration file
If you set the environment variable called $PROJECT_CFG_ROOT (all uppercase), GOP will check that directory for the file named $APP.conf
If you did not set any of these environment variables, GOP will look for a file named $APP.conf in /etc/$PROJECT
It should be emphasized that GOP will check only one location. It means that if you specified $PROJECT_$APP_CFG_FILE and the file does not exist, GOP will raise an error.
To summarize it:
pathToConfigFile = $PROJECT_$APP_CFG_FILE || $PROJECT_CFG_ROOT/$APP.conf || /etc/$PROJECT/$APP.conf
Overriding configuration ¶
There are certain cases, when you may want to override parts of your configuration. GOP provides a mechanism for doing that. Simply create a JSON file next to the config file that GOP will use. The file should have the same name as that config file, but also have the ".override" extension appended to it. Example:
Config: /etc/my_gop_project/my_gop_app.conf Override: /etc/my_gop_project/my_gop_app.conf.override
In fact, GOP will warn you if it does not find the overrides file. And an empty file will not satisfy it - it has to be a valid JSON.
There is also a restriction to the contents of the overrides file:
- The root element must be an associative array (can be empty)
- The keys of the root element must be strings (section names)
- The values of the root element must be associative arrays (section options)
- The keys and values of the associative arrays that are the values of the root element must be quoted
To illustrate these requirements:
[] # Bad. Root element is not an associative array. {"version": "2"} # Bad. Values of the root element must be associative arrays. {"overrides": {"version": 2}} # Bad. Version is not quoted. {"overrides": {"version": "2"}} # Good. {} # Good. Minimum viable config.
Accessing configuration ¶
You can access the application's configuration via the Cfg property of the app instance returned by gop.Init(). This property has type Config.
Logging ¶
GOP uses Timber (https://github.com/jbert/timber) for logging. A *gop.App instance embeds the interface of timber.Logger, which means all of its methods can be accessed like this:
app := gop.Init("myproject", "myapp") app.Debug("My debug message")
Configuring Logging ¶
The logger is configured during the call to gop.Init(). The following options are available in the gop section of the configuration file (values shown below are default):
log_pattern = "[%D %T] [%L] %S" # Log message format accepted by Timber log_filename = false # Show file path and line number of the method that created log message. # This option may not work with custom log pattern (include %S to avoid it). log_dir = /var/log # Directory where GOP will look for the project's log directory log_file = $log_dir/$project_name/$app.log # Full path to the log file log_level = INFO # Case-insensitive log level accepted by Timber: Finest, Fine, Debug, Trace, Info, Warn, Error, Critical stdout_only_logging = false # Output log to STDOUT instead of the log file
If the path to the log_file does not exist and stdout_only_logging is false, GOP will raise an error.
GOP HTTP Handlers ¶
GOP provides a few HTTP handlers, all beginning with "/gop", that you can enable by setting enable_gop_urls to true in the gop section of your configuration file. Otherwise, GOP will respond with "not enabled" when you will try to access those handlers.
The following handlers are available:
/gop/config/:section/:key When the HTTP verb is PUT, GOP will override the config setting specified by :section and :key (the value should be specified in the body of the request). When the HTTP verb is not PUT, :section and :key are ignored and the method returns the complete config, including any overrides. In fact, you can omit :section and :key altogether, i.e. "/gop/config" will suffice. /gop/status TODO /gop/stack TODO /gop/mem TODO /gop/test?secs=int&kbytes=int TODO GOP "Go in Production" is an attempt to provide a useful set of services for running (primarily http) applications in production service. This includes: - configuration - logging - statsd integration - signal handling - resource management - basic web framework
Index ¶
- func BadRequest(body string) error
- func NotFound(body string) error
- func ServerError(body string) error
- type App
- func (a *App) Finish()
- func (a *App) GetStats() AppStats
- func (a *App) HTTPHandler(u string, h http.Handler)
- func (a *App) HandleFunc(u string, h HandlerFunc, requiredParams ...string) *mux.Route
- func (a *App) HandleMap(hm map[string]func(g *Req) error)
- func (a *App) HandleWebSocketFunc(u string, h HandlerFunc, requiredParams ...string) *mux.Route
- func (a *App) Run()
- func (a *App) Serve(l net.Listener)
- func (a *App) StartGracefulRestart(reason string)
- func (a *App) WrapHandler(h HandlerFunc, requiredParams ...string) http.HandlerFunc
- func (a *App) WrapWebSocketHandler(h HandlerFunc, requiredParams ...string) http.HandlerFunc
- func (a *App) WriteAccessLog(req *Req, dur time.Duration)
- type AppStats
- type Config
- func (cfg *Config) AddOnChangeCallback(f func(cfg *Config))
- func (cfg *Config) AsMap() map[string]map[string]string
- func (cfg *Config) Get(sectionName, optionName string, defaultValue string) (string, bool)
- func (cfg *Config) GetBool(sectionName, optionName string, defaultValue bool) (bool, bool)
- func (cfg *Config) GetDuration(sectionName, optionName string, defaultValue time.Duration) (time.Duration, bool)
- func (cfg *Config) GetFloat32(sectionName, optionName string, defaultValue float32) (float32, bool)
- func (cfg *Config) GetFloat64(sectionName, optionName string, defaultValue float64) (float64, bool)
- func (cfg *Config) GetInt(sectionName, optionName string, defaultValue int) (int, bool)
- func (cfg *Config) GetInt64(sectionName, optionName string, defaultValue int64) (int64, bool)
- func (cfg *Config) GetList(sectionName, optionName string, defaultValue []string) ([]string, bool)
- func (cfg *Config) GetMap(sectionName, kPrefix string, defaultValue map[string]string) (map[string]string, bool)
- func (cfg *Config) GetPath(sectionName, optionName string, defaultValue string) (string, bool)
- func (cfg *Config) PersistentOverride(sectionName, optionName, optionValue string)
- func (cfg *Config) SectionKeys(sectionName string) []string
- func (cfg *Config) Sections() []string
- func (cfg *Config) TransientOverride(sectionName, optionName, optionValue string)
- type ConfigMap
- type ConfigSource
- type HTTPError
- type HandlerFunc
- type Logger
- type Req
- func (g *Req) Param(key string) (string, error)
- func (g *Req) ParamBool(key string) (bool, error)
- func (g *Req) ParamDuration(key string) (time.Duration, error)
- func (g *Req) ParamInt(key string) (int, error)
- func (g *Req) ParamTime(key string) (time.Time, error)
- func (g *Req) Params() map[string]string
- func (g *Req) Render(templateData interface{}, templates ...string) error
- func (g *Req) SendHtml(v []byte) error
- func (g *Req) SendJson(what string, v interface{}) error
- func (g *Req) SendText(v []byte) error
- func (g *Req) WebSocketWriteBinary(buf []byte) error
- func (g *Req) WebSocketWriteText(buf []byte) error
- type StatsdClient
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ServerError ¶
Helper to generate an InternalServerError HTTPError
Types ¶
type App ¶
type App struct { AppName string ProjectName string GorillaRouter *mux.Router // contains filtered or unexported fields }
Represents a gop application. Create with gop.Init(projectName, applicationName)
func (*App) HandleFunc ¶
Register an http handler managed by gop. We use Gorilla muxxer, since it is back-compatible and nice to use :-)
func (*App) HandleWebSocketFunc ¶
func (*App) StartGracefulRestart ¶
func (*App) WrapHandler ¶
func (a *App) WrapHandler(h HandlerFunc, requiredParams ...string) http.HandlerFunc
func (*App) WrapWebSocketHandler ¶
func (a *App) WrapWebSocketHandler(h HandlerFunc, requiredParams ...string) http.HandlerFunc
type Config ¶
type Config struct {
// contains filtered or unexported fields
}
func (*Config) AddOnChangeCallback ¶
func (*Config) AsMap ¶
Get a copy of the config as a map that maps each section to a map that maps the options to the values.
func (*Config) GetBool ¶
Same as Config.Get, but returns the value as boolean. The option value should be one that strconv.ParseBool understands.
func (*Config) GetDuration ¶
func (cfg *Config) GetDuration(sectionName, optionName string, defaultValue time.Duration) (time.Duration, bool)
Same as Config.Get but returns the value as time.Duration. The value in the config file should be in the format that time.ParseDuration() understands.
func (*Config) GetFloat32 ¶
Same as Config.Get, but returns the value as float32.
func (*Config) GetFloat64 ¶
Same as Config.Get, but returns the value as float64
func (*Config) GetInt64 ¶
Same as Config.Get, but returns the value as int64. The integer has to be written in the config in decimal format. This means that for the value written in the config as "08" this method will return 8 instead of 10. And "0x8" will generate an error.
func (*Config) GetList ¶
Return a list of strings for a config value that is written as a comma-separated list. Each value will be stripped out of leading and trailing white spaces as defined by Unicode.
func (*Config) GetPath ¶
Same as Config.Get but consider the string as a filename path and expands ~ characters to the homedir of the current uid
func (*Config) PersistentOverride ¶
func (*Config) SectionKeys ¶
Get a list of options for the named section, including those specified in the override file.
func (*Config) Sections ¶
Get a list of the names of the available sections, including those specified in the override file.
func (*Config) TransientOverride ¶
type ConfigMap ¶
func (*ConfigMap) Add ¶
Set the given option to the specified value for the named section. Create the section if it does not exist.
func (*ConfigMap) Get ¶
Get an option value for the given sectionName. Will return defaultValue if the section or the option does not exist. The second return value is True if the requested option value was returned and False if the default value was returned.
func (*ConfigMap) SectionKeys ¶
Get a list of options for the named section. Will return an empty list if the section does not exist.
type ConfigSource ¶
type HTTPError ¶
Return one of these from a handler to control the error response Returning nil if you have sent your own response (as is typical on success)
var ErrBadRequest HTTPError = HTTPError{Code: http.StatusBadRequest}
var ErrNotFound HTTPError = HTTPError{Code: http.StatusNotFound}
Simple helpers for common HTTP error cases
var ErrServerError HTTPError = HTTPError{Code: http.StatusInternalServerError}
type HandlerFunc ¶
The function signature your http handlers need.
type Req ¶
type Req struct { R *http.Request RealRemoteIP string IsHTTPS bool // Only one of these is valid to use... W *responseWriter WS *websocket.Conn CanBeSlow bool //set this to true to suppress the "Slow Request" warning // contains filtered or unexported fields }
Per request struct. has convenience references to functionality in the app singleton. Passed into the request handler.
func (*Req) SendHtml ¶
SendHtml sends the given []byte with the mimetype "text/html". The []byte must be in UTF-8 encoding.
func (*Req) SendJson ¶
SendJson marshals the given v into JSON and sends it with the mimetype "application/json". what is a human-readable name for the thing being marshalled.
func (*Req) SendText ¶
SendText sends the given []byte with the mimetype "text/plain". The []byte must be in UTF-8 encoding.
func (*Req) WebSocketWriteBinary ¶
func (*Req) WebSocketWriteText ¶
type StatsdClient ¶
type StatsdClient struct {
// contains filtered or unexported fields
}
func (*StatsdClient) Dec ¶
func (s *StatsdClient) Dec(stat string, value int64)
func (*StatsdClient) Gauge ¶
func (s *StatsdClient) Gauge(stat string, value int64)
func (*StatsdClient) GaugeDelta ¶
func (s *StatsdClient) GaugeDelta(stat string, value int64)
func (*StatsdClient) Inc ¶
func (s *StatsdClient) Inc(stat string, value int64)
func (*StatsdClient) Timing ¶
func (s *StatsdClient) Timing(stat string, delta int64)