gop

package module
v0.0.0-...-6c1ebcb Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 5, 2015 License: BSD-3-Clause Imports: 24 Imported by: 0

README

Gop

Gop (Go-in-Production) is an application container framework.

Gop makes it easier to write, deploy and maintain Go applications in a production environment.

Gop strongly follows convention-over-configuration principles. Things like file locations and formats are standardized wherever it makes sense for them to be.

Features

Gop applications get the following features:

  • Config file
  • Logging
  • HTTP microframework
  • Graceful restarts
  • Process manager
  • Resource tracking and limits
  • Runtime config overrides
  • Introspection
  • Go runtime control

More information about each of these features is below.

Getting started

Gop requires go 1.2 or higher.

First, install the gop package:

go get github.com/trendmicro/gop

Gop applications are identified by a project name and an app name. Let's imagine our app is called helloworld and is part of a project called gopexamples.

Create helloworld.go:

package main

import (
	"github.com/trendmicro/gop"
)

// hello is a basic HTTP handler
func hello(g *gop.Req) error {
	return g.SendText([]byte("Hello, world!\n"))
}

// main initializes the gop app
func main() {
	app := gop.Init("gopexamples", "helloworld")
	app.HandleFunc("/hello", hello)
	app.Run()
}

Every gop app has a config file.

Create /etc/gopexamples/helloworld.conf. The filename is important. It must match the project and app names of your app.

[gop]
listen_addr=:8888
stdout_only_logging=true

And run your app:

go run helloworld.go

You should be able to access your handler at http://localhost:8888/hello.

Getting help

Visit the Gop website.

Issues and bugs can be reported at the Github issue tracker for gop.

Contents

Authors

  • John Berthels
  • Mark Boyd

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func BadRequest

func BadRequest(body string) error

Helper to generate a BadRequest HTTPError

func NotFound

func NotFound(body string) error

Helper to generate a NotFound HTTPError

func ServerError

func ServerError(body string) error

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 Init

func Init(projectName, appName string) *App

Set up the application. Reads config. Panic if runtime environment is deficient.

func InitCmd

func InitCmd(projectName, appName string) *App

For test code and command line tools

func (*App) Finish

func (a *App) Finish()

Shut down the app cleanly. (Needed to flush logs)

func (*App) GetStats

func (a *App) GetStats() AppStats

func (*App) HTTPHandler

func (a *App) HTTPHandler(u string, h http.Handler)

func (*App) HandleFunc

func (a *App) HandleFunc(u string, h HandlerFunc, requiredParams ...string) *mux.Route

Register an http handler managed by gop. We use Gorilla muxxer, since it is back-compatible and nice to use :-)

func (*App) HandleMap

func (a *App) HandleMap(hm map[string]func(g *Req) error)

func (*App) HandleWebSocketFunc

func (a *App) HandleWebSocketFunc(u string, h HandlerFunc, requiredParams ...string) *mux.Route

func (*App) Run

func (a *App) Run()

func (*App) Serve

func (a *App) Serve(l net.Listener)

func (*App) StartGracefulRestart

func (a *App) StartGracefulRestart(reason string)

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

func (*App) WriteAccessLog

func (a *App) WriteAccessLog(req *Req, dur time.Duration)

type AppStats

type AppStats struct {
	// contains filtered or unexported fields
}

type Config

type Config struct {
	// contains filtered or unexported fields
}

func (*Config) AddOnChangeCallback

func (cfg *Config) AddOnChangeCallback(f func(cfg *Config))

func (*Config) AsMap

func (cfg *Config) AsMap() map[string]map[string]string

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) Get

func (cfg *Config) Get(sectionName, optionName string, defaultValue string) (string, bool)

func (*Config) GetBool

func (cfg *Config) GetBool(sectionName, optionName string, defaultValue bool) (bool, bool)

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

func (cfg *Config) GetFloat32(sectionName, optionName string, defaultValue float32) (float32, bool)

Same as Config.Get, but returns the value as float32.

func (*Config) GetFloat64

func (cfg *Config) GetFloat64(sectionName, optionName string, defaultValue float64) (float64, bool)

Same as Config.Get, but returns the value as float64

func (*Config) GetInt

func (cfg *Config) GetInt(sectionName, optionName string, defaultValue int) (int, bool)

Same as Config.Get, but returns the value as int.

func (*Config) GetInt64

func (cfg *Config) GetInt64(sectionName, optionName string, defaultValue int64) (int64, bool)

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

func (cfg *Config) GetList(sectionName, optionName string, defaultValue []string) ([]string, bool)

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) GetMap

func (cfg *Config) GetMap(sectionName, kPrefix string, defaultValue map[string]string) (map[string]string, bool)

func (*Config) GetPath

func (cfg *Config) GetPath(sectionName, optionName string, defaultValue string) (string, bool)

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 (cfg *Config) PersistentOverride(sectionName, optionName, optionValue string)

func (*Config) SectionKeys

func (cfg *Config) SectionKeys(sectionName string) []string

Get a list of options for the named section, including those specified in the override file.

func (*Config) Sections

func (cfg *Config) Sections() []string

Get a list of the names of the available sections, including those specified in the override file.

func (*Config) TransientOverride

func (cfg *Config) TransientOverride(sectionName, optionName, optionValue string)

type ConfigMap

type ConfigMap map[string]map[string]string

func (*ConfigMap) Add

func (cfgMap *ConfigMap) Add(sectionName, optionName, optionValue string)

Set the given option to the specified value for the named section. Create the section if it does not exist.

func (*ConfigMap) Get

func (cfgMap *ConfigMap) Get(sectionName, optionName string, defaultValue string) (string, bool)

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

func (cfgMap *ConfigMap) SectionKeys(sectionName string) []string

Get a list of options for the named section. Will return an empty list if the section does not exist.

func (*ConfigMap) Sections

func (cfgMap *ConfigMap) Sections() []string

Get a list of the names of the avaliable sections.

type ConfigSource

type ConfigSource interface {
	Get(sectionName, optionName string, defaultValue string) (string, bool)
	Add(sectionName, optionName, optionValue string)
	Sections() []string
	SectionKeys(sectionName string) []string
}

type HTTPError

type HTTPError struct {
	Code int
	Body string
}

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}

func (HTTPError) Error

func (h HTTPError) Error() string

To satisfy the interface only

func (HTTPError) Write

func (h HTTPError) Write(w *responseWriter)

type HandlerFunc

type HandlerFunc func(g *Req) error

The function signature your http handlers need.

type Logger

type Logger timber.Logger

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) Param

func (g *Req) Param(key string) (string, error)

func (*Req) ParamBool

func (g *Req) ParamBool(key string) (bool, error)

func (*Req) ParamDuration

func (g *Req) ParamDuration(key string) (time.Duration, error)

func (*Req) ParamInt

func (g *Req) ParamInt(key string) (int, error)

func (*Req) ParamTime

func (g *Req) ParamTime(key string) (time.Time, error)

func (*Req) Params

func (g *Req) Params() map[string]string

func (*Req) Render

func (g *Req) Render(templateData interface{}, templates ...string) error

func (*Req) SendHtml

func (g *Req) SendHtml(v []byte) error

SendHtml sends the given []byte with the mimetype "text/html". The []byte must be in UTF-8 encoding.

func (*Req) SendJson

func (g *Req) SendJson(what string, v interface{}) error

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

func (g *Req) SendText(v []byte) error

SendText sends the given []byte with the mimetype "text/plain". The []byte must be in UTF-8 encoding.

func (*Req) WebSocketWriteBinary

func (g *Req) WebSocketWriteBinary(buf []byte) error

func (*Req) WebSocketWriteText

func (g *Req) WebSocketWriteText(buf []byte) error

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)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL