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 "???"
|
|||
|
}
|
|||
|
}
|