139 lines
3.5 KiB
Go
139 lines
3.5 KiB
Go
package journal
|
||
|
||
import (
|
||
"fmt"
|
||
)
|
||
|
||
// AttrKey holds the key part of a key/value (attribute) pair. Passing an
|
||
// uninitialised (or invalid) AttrKey to other journal methods will cause the
|
||
// attribute to be ignored; check for errors from NewAttrKey to ensure that
|
||
// your keys are valid ahead of time.
|
||
type AttrKey struct {
|
||
// key is written directly to the journal socket. If it is empty, then
|
||
// the attribute should be silently discarded. By having it unexported,
|
||
// we can ensure that library users can only ever have valid string
|
||
// values here.
|
||
key string
|
||
}
|
||
|
||
// Key returns the string value of the key. If the attribute is invalid, it
|
||
// returns an empty string.
|
||
func (ak AttrKey) Key() string {
|
||
return ak.key
|
||
}
|
||
|
||
// Valid returns true if ak is valid.
|
||
func (ak AttrKey) Valid() bool {
|
||
return ak.key != ""
|
||
}
|
||
|
||
// NewAttrKey initialises and returns an AttrKey that may be used when
|
||
// constructing key/value (attribute) pairs for logging. If the key is invalid,
|
||
// then an error will be returned (and the returned key value will be invalid,
|
||
// and any attribute using that key will silently be omitted from the logs).
|
||
// Rules for valid attribute keys:
|
||
// - must not be empty;
|
||
// - must not begin with an underscore '_';
|
||
// - must only contain uppercase ASCII 'A'–'Z', digits '0'–'9', or
|
||
// underscores;
|
||
// - must be < 256 characters.
|
||
func NewAttrKey(key string) (AttrKey, error) {
|
||
if err := AttrKeyValid(key); err != nil {
|
||
return AttrKey{}, err
|
||
}
|
||
return AttrKey{
|
||
key: key,
|
||
}, nil
|
||
}
|
||
|
||
// MustAttrKey returns an AttrKey for the given string. If the string is not a
|
||
// valid systemd attribute key, it returns an invalid AttrKey that will cause
|
||
// the attribute not to be emitted to the journal.
|
||
func MustAttrKey(key string) AttrKey {
|
||
if err := AttrKeyValid(key); err != nil {
|
||
return AttrKey{}
|
||
}
|
||
return AttrKey{
|
||
key: key,
|
||
}
|
||
}
|
||
|
||
// AttrKeyValid checks the given attribute key and returns an error if there is
|
||
// a fault with it.
|
||
func AttrKeyValid(key string) error {
|
||
switch {
|
||
case key == "":
|
||
return &InvalidAttrKey{
|
||
Key: key,
|
||
Reason: AttrKeyEmpty,
|
||
}
|
||
case key[0] == '_':
|
||
return &InvalidAttrKey{
|
||
Key: key,
|
||
Reason: AttrKeyTrusted,
|
||
}
|
||
case len(key) >= 256:
|
||
return &InvalidAttrKey{
|
||
Key: key,
|
||
Reason: AttrKeyLength,
|
||
}
|
||
case !attrKeyValidChars(key):
|
||
return &InvalidAttrKey{
|
||
Key: key,
|
||
Reason: AttrKeyInvalidChars,
|
||
}
|
||
default:
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// attrKeyValidChars returns true if the given key comprises only ASCII 'A'–'Z',
|
||
// '0'–'9' and underscores.
|
||
func attrKeyValidChars(key string) bool {
|
||
for _, b := range key {
|
||
switch {
|
||
case b >= 'A' && b <= 'Z':
|
||
case b >= '0' && b <= '9':
|
||
case b == '_':
|
||
|
||
default:
|
||
return false
|
||
}
|
||
}
|
||
return true
|
||
}
|
||
|
||
// InvalidAttrKey details why a given attribute key is invalid.
|
||
type InvalidAttrKey struct {
|
||
Key string
|
||
Reason InvalidAttrKeyReason
|
||
}
|
||
|
||
func (iak *InvalidAttrKey) Error() string {
|
||
return fmt.Sprintf("invalid systemd journal attribute key %q: %s", iak.Key, iak.Reason)
|
||
}
|
||
|
||
type InvalidAttrKeyReason int
|
||
|
||
const (
|
||
AttrKeyEmpty InvalidAttrKeyReason = iota
|
||
AttrKeyTrusted
|
||
AttrKeyLength
|
||
AttrKeyInvalidChars
|
||
)
|
||
|
||
func (iar InvalidAttrKeyReason) String() string {
|
||
switch iar {
|
||
case AttrKeyEmpty:
|
||
return "key is empty"
|
||
case AttrKeyTrusted:
|
||
return "key is trusted (begins with '_' character)"
|
||
case AttrKeyLength:
|
||
return "key is too long (max 256 chars)"
|
||
case AttrKeyInvalidChars:
|
||
return "key contains invalid character (only 'A'–'Z', '0'–'9', or '_' allowed)"
|
||
default:
|
||
return "???"
|
||
}
|
||
}
|