Releases: graniticio/granitic
v2.2.2
v2.2.1
Fixes for CodeQL analysis issues
v2.2.0
Granitic 2.2 Release Notes
Granitic 2.2 adds features and fixes that are backwards-compatible with code based on Granitic 2.0.x
Logging
JSON structured access and application logging
Application logs and access logs can now configured to output a user-defined JSON structure for each log event.
Refer to the reference manual for application logging and the HTTP server facility for more details.
STDOUT access logging
The HTTP Server access log can now write to STDOUT
if you set HTTPServer.AccessLog.LogPath
to STDOUT
in configuration.
Multiple ContextFilters
Your application can now have as more than one component that implements logging.ContextFilter. If more than one component is found, they will be merged into a logging.PrioritisedContextFilter
You can control the how keys present in more than one ContextFilter are resolved to a single value by having your ContextFilters implement logging.FilterPriority
Application start up
Save merged configuration
Supply the -m
flag and a path to a file when starting your application will cause Granitic to write its final, merged view of your application's configuration to that file (as JSON) and then exit.
This is useful when debugging problems introduced by merging configuration files.
Instance IDs
Setting the -u
flag when starting your application will cause Granitic to generate a V4 UUID and use that as the ID for that instance of your application.
Your application's instance ID is now available as configuration at the path System.InstanceID
Query Manager
Slices as parameters
When using the query manager (either directly or via the RDBMS interfaces) to construct a parameterised query, you may now provide slices/arrays of some types as parameters. The default behaviour is to format the slice as a comma separated list. Slices may contain any of the types supported as individual parameters - basic int types, booleans, strings and their nilable equivalents.
Web Services
Slices as parameters in query strings and request paths
Request path and query binding now supports binding into a slice.
The parameter value should be expressed as a comma-separated list (e.g. /some/p,a,t,h
or /path?a=1,2,3&b=true,false
)
Target slices can be a slice of any Go basic type (except uintptr
, complex64
and complex128
) and any
nilable type.
Bug fixes
Query manager default configuration
Enabling the query manager facility with its default configuration was causing a fatal error on application startup.
2.2 JSON logging preview (v3)
v2.2.0-20200427 ContextFilter initialisation order fix
2.2 JSON logging preview (v2)
v2.2.0-20200424 Log level mapping
2.2 JSON logging preview
v2.2.0-20200420 Support for standard access logging format
v2.1.0
Granitic 2.1 Release Notes
Granitic 2.1 adds features and fixes that are backwards-compatible with code based on Granitic 2.0.x
See the milestone on GitHub
for a complete list of issues resolved in this release.
Access Logging
The access logging feature of the HTTPServer facility has the following changed behaviour.
- Improved stopping behaviour (silently ignores LogRequest when application is stopping) and closes log line channel correctly
- Now explicitly switches to synchronous/blocking logging when
HTTPServer.AccessLog.LineBufferSize
is set to zero or less. Default is 10. - Data stored in a
context.Context
can now be logged in access log lines (using the%{KEY}X
verb) as long
as you have created a component that implements logging.ContextFilter
Application logging
Data stored in a context.Context
can now be logged in the prefix of applicaiton log lines (using the %{KEY}X
verb) as long
as you have created a component that implements logging.ContextFilter
HTTP Response Status Codes
The default set of HTTP status codes (described here) can now be overridden in
configuration as described here
UUIDs
The function uuid.V4()
can now be used to generate version four UUIDs. The implementation is fast and uses Go's
crypto/rand
package to create the random numbers on which they are based.
You can now also configure the HTTPSever facility to assign UUID V4 IDs to each request
Request IDs
If request identification has been set up, your code can now find the string
ID for the current request by calling ws.RequestID(context.Context)
v2.0.2
Fixes:
- rdbms.Client missing InsertQIDParam method
- iam.Identifier.Identifty misnamed as iam.Identifier.IDentify
See the v2.0.0 release notes for major changes and v1->v2 migration
v2.0.1
Fixed broken RDBMS client decorator test.
See the release notes for 2.0.0 for major changes
v2.0.0
Granitic 2.0 Release Notes
Granitic 2.0 is a major release of Granitic focusing on YAML support, Go module support, streamlining of web service code, improvements to grnc-bind
, code quality and documentation.
This release is not backwards compatible, refer to the migration guide at the bottom of these notes for more information.
YAML
Granitic now supports YAML for configuration and component definition files. This involves the use of a third-party YAML parser and so to preserve Granitic's principle of having no dependencies, you must download the additional granitic-yaml project from GitHub or add it as a Go module dependency (see below).
The default file format for Granitic is currently still JSON and all documentation and examples will continue to use JSON, but YAML versions of the tutorial source code are now available.
Note you will need to change your application's main function to
func main() {
granitic-yaml.StartGraniticWithYaml(bindings.Components())
}
New default locations for files
The previous default locations for application configuration (resource/config
) and component definitions (resource/components
) were too verbose and have been deprecated. The new preferred locations are config
and comp-def
.
grnc-project
has been modified to create projects with these new locations. The empty files it creates are now config/base.json
and comp-def/common.json
and the generated entrypoint file is main.go
The old locations are still respected, but you will see a warning when you use them. Support for the old locations will be removed in a future version of Granitic.
Reference documentation
Granitic now has a reference manual, intended to compliment the information in the Godoc.
You can find this manual in doc/ref/index.md
or on the Granitic website.
Go modules
Grantic 2 is compatible with the requirements of Go modules including
semantic import verisioning. As such Granitic
now requires the use of Go 1.11 or later.
Your applications should declare their dependency on Granitic in their go.mod
file with:
require github.com/graniticio/granitic/v2 v2
or (if you are using YAML configuration and component files)
require github.com/graniticio/granitic-yaml/v2 v2
Wherever your code (or component definition files) imports Granitic types, the import statements should be of
the form:
import "github.com/graniticio/granitic/v2/packageName"
Tool support
grnc-project
and grnc-yaml-project
now generate working Granitic projects using modules. A go.mod
will automatically
be created for you.
grnc-bind
and grnc-yaml-bind
have additional support for modules. These features are explained below.
Web service streamlining
Your web service logic component no longer needs to implement handler.WsRequestProcessor or
handler.WsUnmarshallTarget. Instead it just needs
to declare a method with the signature:
ProcessPayload(context.Context, *ws.Request, *ws.Response, *YourStruct)
Where *YourStruct
is a pointer to any type that you want the HTTP request's payload to be parsed into.
If you do not need any body, path or query parameter data parsed (e.g. a simple GET or HEAD), you should continue to implement
handler.WsRequestProcessor.
If you need more control over the struct that is created as your parsing target (e.g. you need to pre-populate it), you
should continue to implement handler.WsUnmarshallTarget.
Request instrumentation
Granitic now includes integration points for adding instrumentation to a web service request and
supporting for propagating that instrumentation to downstream web service requests. A common
use-case for this is to add timing traces to service calls.
See the instrument package documentation for more details.
Request unique identifiers
Granitic now includes integration points for generating unique IDs for web service requests
and having them injected into that request's context.Context
. You need to create a component that implements
IdentifiedRequestContextBuilder
Code quality
Granitic 2 sees significant improvements in file and statement unit test coverage. This release
also see the start of Granitic committing to abiding by all of the advice from the go vet
and
golint
tools.
This has resulted in changes to the names of a number of exported types and the names of some Granitic
facilities. See the migration guide at the bottom of these notes for information on how this might affect your
application.
RDBMS client is now an interface
To make it easier to provide mock implementations for testing, the struct rdbms.RdbmsClient is now the interface
rdbms.Client
grnc-bind
grnc-bind
(and its YAML equivalent grnc-yaml-bind
) have gained a number of additional features
and quality of life improvements.
Validation and error handling
Rather than exit as soon as an error is found,grnc-bind
attempts to continue parsing your
component definition files for as long as possible. This means that multiple errors are now reported
in a single run.
Additional validation has been applied to increase the number of problems detected during the bind
phase instead of during go build
Logging
You can now provide a -l LOGLEVEL
flag to grnc-bind
for more detailed output. Valid
values for LOGLEVEL
are TRACE
, DEBUG
, INFO
, WARN
, ERROR
and FATAL
(case
insensitive). Default is WARN
New symbols for dependency and configuration promises
In addition to the c:
, conf:
, r:
and ref:
prefixes for indicating configuration promises
and component dependencies, you can now also use the symbols $
and +
as an alternative.
For example:
"ComponentName": {
"type": "some.Type",
"A": "$some.config.path",
"B": "+someOtherComponent"
}
If strings in your component definition file start with these new symbols, you can escape them with $$
or ++
Nested components
You can now define components in a nested manner under the field of the parent component
that the nested component should be injected into.
For example:
"artistHandler": {
"type": "handler.WsHandler",
"PathPattern": "$paths.getArtist(^/artist)",
"HTTPMethod": "GET",
"Logic": {
"type": "endpoint.ArtistLogic"
}
}
The only requirement is that you specify a type or a parent template for the nested component.
If you want to be able to refer to the nested component from other components, you need to
provide a name
field, e.g.:
"Logic": {
"type": "endpoint.ArtistLogic",
"name": "artistLogic"
}
Default values
You can now provide a default value along with a configuration promise by including the
default in brackets after the config path. This value will be used if no configuration
is provided to your application that overrides that config path.
For example:
"ComponentName": {
"type": "some.Type",
"A": "$some.config.path(true)",
"B": "$some.other.path(1.2"
}
Note that default values will only be type checked against the fields you are trying to
inject them into at application run time (not during the build phase).
Package aliases
If your component definition files import two packages that clash (because the final part of the
package name is the same), you can define an alias for one of the packages, then refer to the
alias when defining types.
For example:
{
"packages": [
"github.com/graniticio/granitic/v2/ws/handler"
],
"packageAliases": {
"mh": "myproject/handler"
},
"SomeComponent": {
"type": "mh.SomeType"
}
}
Find Granitic installation from go.mod (experimental)
grnc-bind
serialises a copy of Granitic's facility configuration files into your application.
As such it needs to know where to find a copy of Granitic on disk. Previously this required
you to set the $GRANITIC_HOME
environment variable or check Granitic out to a standard location.
In Granitic 2, the go.mod file can instead be used to automatically work out where to find
Granitic (but you still need to set your $GOPATH
environment variable correctly).
This feature has not been fully tested with module proxies so should be considered experimental.
Bug fixes
- Component definition files containing a slice of
float64
could not be bound if the first element was parseable as an int. - The
ServiceErrorManager
was not respecting the value ofErrorCodeUser.ValidateMissing()
when complaining about missing error codes. - Using
ConfigAccessor
to try and push configuration into an unsupported type of target field was not returning an error. - Some configuration parsing errors were causing Granitic to exit rather than return an error
Granitic 1.x to 2.0 migration
Support for Go modules and implementing th...