Compare commits

...

14 Commits

Author SHA1 Message Date
fb11c0c27c syslog: support not using syslog 2023-05-06 00:57:42 -07:00
27cc67d2cf this is why i hate computers 2023-05-04 23:58:51 -07:00
0fe13439b6 moving circleci file to the right place. 2023-05-04 23:57:40 -07:00
fb9caec663 Update CircleCI configuration. 2023-05-04 23:55:26 -07:00
e3e83630b5 Add CircleCI configuration. 2023-05-04 23:54:47 -07:00
c1f06604e3 fix dependency issues. 2023-05-04 23:45:08 -07:00
9091cc7682 syslog: add Spew option.
This is a debug print that spews any arguments passed in.
2023-05-04 23:40:20 -07:00
74ce7bc58a Cleaning up the codebase. 2023-05-04 23:22:35 -07:00
8b2d10209e Clean up the README. 2023-05-04 22:58:21 -07:00
770100b688 fileutil: start working on symlink checking 2023-05-04 22:52:16 -07:00
29630c55a9 packaging is a dead end thus far
I think I'm going to have to write my own rules to do this.
2023-05-04 21:03:08 -07:00
3c2ec896f8 cmd/cruntar: avoid writing files outside archive 2023-05-04 17:20:22 -07:00
7828726ba4 Updating x/sys. 2023-05-04 17:13:06 -07:00
458f3ceaed update dependencies to fix dependabot warnings. 2023-05-04 17:10:41 -07:00
25 changed files with 364 additions and 171 deletions

59
.circleci/config.yml Normal file
View File

@@ -0,0 +1,59 @@
# Use the latest 2.1 version of CircleCI pipeline process engine.
# See: https://circleci.com/docs/2.0/configuration-reference
version: 2.1
commands:
setup-bazel:
description: |
Setup the Bazel build system used for building the repo
steps:
- run:
name: Add Bazel Apt repository
command: |
sudo apt install curl gnupg
curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor > bazel.gpg
sudo mv bazel.gpg /etc/apt/trusted.gpg.d/
echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
- run:
name: Install Bazel from Apt
command: sudo apt update && sudo apt install bazel
# Define a job to be invoked later in a workflow.
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
jobs:
testbuild:
working_directory: ~/repo
# Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub.
# See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor
docker:
- image: circleci/golang:1.15.8
# Add steps to the job
# See: https://circleci.com/docs/2.0/configuration-reference/#steps
steps:
- checkout
- setup-bazel
- restore_cache:
keys:
- go-mod-v4-{{ checksum "go.sum" }}
- run:
name: Install Dependencies
command: go mod download
- save_cache:
key: go-mod-v4-{{ checksum "go.sum" }}
paths:
- "/go/pkg/mod"
- run:
name: Run tests
command: bazel test //...
- run:
name: Run build
command: bazel build //...
- store_test_results:
path: /tmp/test-reports
# Invoke jobs via workflows
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
workflows:
testbuild:
jobs:
- testbuild

View File

@@ -1,10 +1,12 @@
GOUTILS GOUTILS
### Note: this repo is archived and not being maintained here anymore.
This is a collection of small utility code I've written in Go; the `cmd/` This is a collection of small utility code I've written in Go; the `cmd/`
directory has a number of command-line utilities. Rather than keep all directory has a number of command-line utilities. Rather than keep all
of these in superfluous repositories of their own, I'm putting them here. of these in superfluous repositories of their own, or rewriting them
for each project, I'm putting them here.
The project can be built with the standard Go tooling, or it can be built
with Bazel.
Contents: Contents:

View File

@@ -1,5 +1,7 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
### Go tooling, including Gazelle to generate and maintain BUILD files.
http_archive( http_archive(
name = "io_bazel_rules_go", name = "io_bazel_rules_go",
sha256 = "6b65cb7917b4d1709f9410ffe00ecf3e160edf674b78c54a894471320862184f", sha256 = "6b65cb7917b4d1709f9410ffe00ecf3e160edf674b78c54a894471320862184f",
@@ -20,20 +22,11 @@ http_archive(
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
############################################################
# Define your own dependencies here using go_repository.
# Else, dependencies declared by rules_go/gazelle will be used.
# The first declaration of an external repository "wins".
############################################################
load("//:deps.bzl", "go_dependencies") load("//:deps.bzl", "go_dependencies")
# gazelle:repository_macro deps.bzl%go_dependencies # gazelle:repository_macro deps.bzl%go_dependencies
go_dependencies() go_dependencies()
go_rules_dependencies() go_rules_dependencies()
go_register_toolchains(version = "1.20.4") go_register_toolchains(version = "1.20.4")
gazelle_dependencies() gazelle_dependencies()

View File

@@ -45,13 +45,6 @@ func sha512Slicer(bs []byte) []byte {
return sum[:] return sum[:]
} }
var sliceFunctions = map[string]func([]byte) []byte{
"sha224": sha224Slicer,
"sha256": sha256Slicer,
"sha384": sha384Slicer,
"sha512": sha512Slicer,
}
// Hash represents a generic hash function that may or may not be secure. It // Hash represents a generic hash function that may or may not be secure. It
// satisfies the hash.Hash interface. // satisfies the hash.Hash interface.
type Hash struct { type Hash struct {

View File

@@ -94,7 +94,7 @@ func NoError(err error, s ...string) {
} }
if nil != err { if nil != err {
die(err.Error()) die(err.Error(), s...)
} }
} }
@@ -170,5 +170,5 @@ func ErrorEqT(t *testing.T, expected, actual error) {
should = fmt.Sprintf("have '%s'", actual) should = fmt.Sprintf("have '%s'", actual)
} }
die(fmt.Sprintf("assert.Error2: expected '%s', but %s", expected, should)) t.Fatalf("assert.Error2: expected '%s', but %s", expected, should)
} }

View File

@@ -10,9 +10,9 @@ import (
"strings" "strings"
"time" "time"
"github.com/cloudflare/cfssl/helpers"
"git.wntrmute.dev/kyle/goutils/die" "git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/lib" "git.wntrmute.dev/kyle/goutils/lib"
"github.com/cloudflare/cfssl/helpers"
) )
var warnOnly bool var warnOnly bool

View File

@@ -8,10 +8,10 @@ import (
"os" "os"
"time" "time"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/revoke"
"git.wntrmute.dev/kyle/goutils/die" "git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/lib" "git.wntrmute.dev/kyle/goutils/lib"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/revoke"
) )
func printRevocation(cert *x509.Certificate) { func printRevocation(cert *x509.Certificate) {

View File

@@ -5,7 +5,10 @@ go_library(
srcs = ["main.go"], srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/cruntar", importpath = "git.wntrmute.dev/kyle/goutils/cmd/cruntar",
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = ["//die"], deps = [
"//die",
"//fileutil",
],
) )
go_binary( go_binary(

View File

@@ -12,6 +12,7 @@ import (
"path/filepath" "path/filepath"
"git.wntrmute.dev/kyle/goutils/die" "git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/fileutil"
) )
var ( var (
@@ -56,7 +57,7 @@ func processFile(tfr *tar.Reader, hdr *tar.Header, top string) error {
} }
filePath := filepath.Clean(filepath.Join(top, hdr.Name)) filePath := filepath.Clean(filepath.Join(top, hdr.Name))
switch hdr.Typeflag { switch hdr.Typeflag {
case tar.TypeReg, tar.TypeRegA: case tar.TypeReg:
file, err := os.Create(filePath) file, err := os.Create(filePath)
if err != nil { if err != nil {
return err return err
@@ -92,6 +93,17 @@ func processFile(tfr *tar.Reader, hdr *tar.Header, top string) error {
return err return err
} }
case tar.TypeSymlink: case tar.TypeSymlink:
if !fileutil.ValidateSymlink(hdr.Linkname, top) {
return fmt.Errorf("symlink %s is outside the top-level %s",
hdr.Linkname, top)
}
path := linkTarget(hdr.Linkname, top)
if ok, err := filepath.Match(top+"/*", filepath.Clean(path)); !ok {
return fmt.Errorf("symlink %s isn't in %s", hdr.Linkname, top)
} else if err != nil {
return err
}
err := os.Symlink(linkTarget(hdr.Linkname, top), filePath) err := os.Symlink(linkTarget(hdr.Linkname, top), filePath)
if err != nil { if err != nil {
return err return err

View File

@@ -6,8 +6,8 @@ go_library(
importpath = "git.wntrmute.dev/kyle/goutils/cmd/showimp", importpath = "git.wntrmute.dev/kyle/goutils/cmd/showimp",
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
"//dbg",
"//die", "//die",
"//logging",
], ],
) )

View File

@@ -12,36 +12,23 @@ import (
"sort" "sort"
"strings" "strings"
"git.wntrmute.dev/kyle/goutils/dbg"
"git.wntrmute.dev/kyle/goutils/die" "git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/logging"
) )
var ( var (
gopath string gopath string
project string project string
debug bool
) )
var ( var (
stdLibRegexp = regexp.MustCompile(`^\w+(/\w+)*$`) debug = dbg.New()
sourceRegexp = regexp.MustCompile(`^[^.].*\.go$`)
log = logging.NewConsole()
imports = map[string]bool{}
fset = &token.FileSet{} fset = &token.FileSet{}
imports = map[string]bool{}
sourceRegexp = regexp.MustCompile(`^[^.].*\.go$`)
stdLibRegexp = regexp.MustCompile(`^\w+(/\w+)*$`)
) )
func debugf(format string, args ...interface{}) {
if debug {
fmt.Printf(format, args...)
}
}
func debugln(args ...interface{}) {
if debug {
fmt.Println(args...)
}
}
func init() { func init() {
gopath = os.Getenv("GOPATH") gopath = os.Getenv("GOPATH")
if gopath == "" { if gopath == "" {
@@ -75,7 +62,7 @@ func walkFile(path string, info os.FileInfo, err error) error {
return nil return nil
} }
debugln(path) debug.Println(path)
f, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly) f, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)
if err != nil { if err != nil {
@@ -85,16 +72,16 @@ func walkFile(path string, info os.FileInfo, err error) error {
for _, importSpec := range f.Imports { for _, importSpec := range f.Imports {
importPath := strings.Trim(importSpec.Path.Value, `"`) importPath := strings.Trim(importSpec.Path.Value, `"`)
if stdLibRegexp.MatchString(importPath) { if stdLibRegexp.MatchString(importPath) {
debugln("standard lib:", importPath) debug.Println("standard lib:", importPath)
continue continue
} else if strings.HasPrefix(importPath, project) { } else if strings.HasPrefix(importPath, project) {
debugln("internal import:", importPath) debug.Println("internal import:", importPath)
continue continue
} else if strings.HasPrefix(importPath, "golang.org/") { } else if strings.HasPrefix(importPath, "golang.org/") {
debugln("extended lib:", importPath) debug.Println("extended lib:", importPath)
continue continue
} }
debugln("import:", importPath) debug.Println("import:", importPath)
imports[importPath] = true imports[importPath] = true
} }
@@ -108,7 +95,7 @@ func main() {
var noVendor bool var noVendor bool
flag.StringVar(&ignoreLine, "i", "", "comma-separated list of directories to ignore") flag.StringVar(&ignoreLine, "i", "", "comma-separated list of directories to ignore")
flag.BoolVar(&noVendor, "nv", false, "ignore the vendor directory") flag.BoolVar(&noVendor, "nv", false, "ignore the vendor directory")
flag.BoolVar(&debug, "v", false, "log debugging information") flag.BoolVar(&debug.Enabled, "v", false, "log debugging information")
flag.Parse() flag.Parse()
if noVendor { if noVendor {

View File

@@ -55,21 +55,21 @@ func To(w io.WriteCloser) *DebugPrinter {
} }
// Print calls fmt.Print if Enabled is true. // Print calls fmt.Print if Enabled is true.
func (dbg DebugPrinter) Print(v ...interface{}) { func (dbg *DebugPrinter) Print(v ...interface{}) {
if dbg.Enabled { if dbg.Enabled {
fmt.Fprint(dbg.out, v...) fmt.Fprint(dbg.out, v...)
} }
} }
// Println calls fmt.Println if Enabled is true. // Println calls fmt.Println if Enabled is true.
func (dbg DebugPrinter) Println(v ...interface{}) { func (dbg *DebugPrinter) Println(v ...interface{}) {
if dbg.Enabled { if dbg.Enabled {
fmt.Fprintln(dbg.out, v...) fmt.Fprintln(dbg.out, v...)
} }
} }
// Printf calls fmt.Printf if Enabled is true. // Printf calls fmt.Printf if Enabled is true.
func (dbg DebugPrinter) Printf(format string, v ...interface{}) { func (dbg *DebugPrinter) Printf(format string, v ...interface{}) {
if dbg.Enabled { if dbg.Enabled {
fmt.Fprintf(dbg.out, format, v...) fmt.Fprintf(dbg.out, format, v...)
} }

View File

@@ -91,6 +91,13 @@ def go_dependencies():
sum = "h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=", sum = "h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=",
version = "v1.0.21", version = "v1.0.21",
) )
go_repository(
name = "com_github_hashicorp_go_syslog",
importpath = "github.com/hashicorp/go-syslog",
sum = "h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=",
version = "v1.0.0",
)
go_repository( go_repository(
name = "com_github_jessevdk_go_flags", name = "com_github_jessevdk_go_flags",
importpath = "github.com/jessevdk/go-flags", importpath = "github.com/jessevdk/go-flags",
@@ -304,8 +311,8 @@ def go_dependencies():
go_repository( go_repository(
name = "org_golang_x_crypto", name = "org_golang_x_crypto",
importpath = "golang.org/x/crypto", importpath = "golang.org/x/crypto",
sum = "h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=", sum = "h1:Qwe1rC8PSniVfAFPFJeyUkB+zcysC3RgJBAGk7eqBEU=",
version = "v0.0.0-20201012173705-84dcc777aaee", version = "v0.0.0-20220314234659-1baeb1ce4c0b",
) )
go_repository( go_repository(
name = "org_golang_x_lint", name = "org_golang_x_lint",
@@ -316,26 +323,26 @@ def go_dependencies():
go_repository( go_repository(
name = "org_golang_x_net", name = "org_golang_x_net",
importpath = "golang.org/x/net", importpath = "golang.org/x/net",
sum = "h1:mUVeFHoDKis5nxCAzoAi7E8Ghb86EXh/RK6wtvJIqRY=", sum = "h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=",
version = "v0.0.0-20201010224723-4f7140c49acb", version = "v0.0.0-20211112202133-69e39bad7dc2",
) )
go_repository( go_repository(
name = "org_golang_x_sys", name = "org_golang_x_sys",
importpath = "golang.org/x/sys", importpath = "golang.org/x/sys",
sum = "h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=", sum = "h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=",
version = "v0.0.0-20200930185726-fdedc70b468f", version = "v0.0.0-20220412211240-33da011f77ad",
) )
go_repository( go_repository(
name = "org_golang_x_term", name = "org_golang_x_term",
importpath = "golang.org/x/term", importpath = "golang.org/x/term",
sum = "h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=", sum = "h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=",
version = "v0.0.0-20201117132131-f5c789dd3221", version = "v0.0.0-20201126162022-7de9c90e9dd1",
) )
go_repository( go_repository(
name = "org_golang_x_text", name = "org_golang_x_text",
importpath = "golang.org/x/text", importpath = "golang.org/x/text",
sum = "h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=", sum = "h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=",
version = "v0.3.3", version = "v0.3.6",
) )
go_repository( go_repository(
name = "org_golang_x_tools", name = "org_golang_x_tools",

View File

@@ -2,8 +2,53 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "fileutil", name = "fileutil",
srcs = ["fileutil.go"], srcs = [
"fileutil.go",
"fileutil_windows.go",
"symlinks.go",
],
importpath = "git.wntrmute.dev/kyle/goutils/fileutil", importpath = "git.wntrmute.dev/kyle/goutils/fileutil",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = ["@org_golang_x_sys//unix"], deps = select({
"@io_bazel_rules_go//go/platform:aix": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:android": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:darwin": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:illumos": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:ios": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:js": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:plan9": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:solaris": [
"@org_golang_x_sys//unix",
],
"//conditions:default": [],
}),
) )

View File

@@ -1,3 +1,6 @@
//go:build !windows
// +build !windows
// Package fileutil contains common file functions. // Package fileutil contains common file functions.
package fileutil package fileutil

View File

@@ -0,0 +1,49 @@
//go:build windows
// +build windows
// Package fileutil contains common file functions.
package fileutil
import (
"errors"
"os"
)
// FileDoesExist returns true if the file exists.
func FileDoesExist(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
// DirectoryDoesExist returns true if the file exists.
func DirectoryDoesExist(path string) bool {
fi, err := os.Stat(path)
if err != nil {
return false
}
return fi.Mode().IsDir()
}
const (
// AccessExists checks whether the file exists. This is invalid outside of
// Unix systems.
AccessExists = 0
// AccessRead checks whether the user has read permissions on
// the file. This is invalid outside of Unix systems.
AccessRead = 0
// AccessWrite checks whether the user has write permissions
// on the file. This is invalid outside of Unix systems.
AccessWrite = 0
// AccessExec checks whether the user has executable
// permissions on the file. This is invalid outside of Unix systems.
AccessExec = 0
)
// Access is a Unix-only call, and has no meaning on Windows.
func Access(path string, mode int) error {
return errors.New("fileutil: Access is meaningless on Windows")
}

16
fileutil/symlinks.go Normal file
View File

@@ -0,0 +1,16 @@
package fileutil
import (
"path/filepath"
"strings"
)
// ValidateSymlink checks to make sure a symlink exists in some top-level
// directory.
func ValidateSymlink(symlink, topLevel string) bool {
target, err := filepath.EvalSymlinks(symlink)
if err != nil {
return false
}
return strings.HasPrefix(target, topLevel)
}

13
go.mod
View File

@@ -4,19 +4,14 @@ go 1.20
require ( require (
github.com/cloudflare/cfssl v1.5.0 github.com/cloudflare/cfssl v1.5.0
github.com/hashicorp/go-syslog v1.0.0
github.com/kr/text v0.2.0 github.com/kr/text v0.2.0
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.12.0 github.com/pkg/sftp v1.12.0
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.6.1
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
) )
require ( require github.com/davecgh/go-spew v1.1.1
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/certificate-transparency-go v1.0.21 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)

15
go.sum
View File

@@ -18,6 +18,8 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
@@ -70,22 +72,31 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200124225646-8b5121be2f68/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200124225646-8b5121be2f68/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b h1:Qwe1rC8PSniVfAFPFJeyUkB+zcysC3RgJBAGk7eqBEU=
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=

View File

@@ -89,7 +89,7 @@ func Duration(d time.Duration) string {
if d >= yearDuration { if d >= yearDuration {
years := d / yearDuration years := d / yearDuration
s += fmt.Sprintf("%dy", years) s += fmt.Sprintf("%dy", years)
d -= (years * yearDuration) d -= years * yearDuration
} }
if d >= dayDuration { if d >= dayDuration {
@@ -103,7 +103,7 @@ func Duration(d time.Duration) string {
d %= 1 * time.Second d %= 1 * time.Second
hours := d / time.Hour hours := d / time.Hour
d -= (hours * time.Hour) d -= hours * time.Hour
s += fmt.Sprintf("%dh%s", hours, d) s += fmt.Sprintf("%dh%s", hours, d)
return s return s
} }

View File

@@ -8,6 +8,67 @@ import (
) )
// Logger provides a standardised logging interface. // Logger provides a standardised logging interface.
//
// Log messages consist of four components:
//
// 1. The **level** attaches a notion of priority to the log message.
// Several log levels are available:
//
// + FATAL (32): the system is in an unsuable state, and cannot
// continue to run. Most of the logging for this will cause the
// program to exit with an error code.
// + CRITICAL (16): critical conditions. The error, if uncorrected, is
// likely to cause a fatal condition shortly. An example is running
// out of disk space. This is something that the ops team should get
// paged for.
// + ERROR (8): error conditions. A single error doesn't require an
// ops team to be paged, but repeated errors should often trigger a
// page based on threshold triggers. An example is a network
// failure: it might be a transient failure (these do happen), but
// most of the time it's self-correcting.
// + WARNING (4): warning conditions. An example of this is a bad
// request sent to a server. This isn't an error on the part of the
// program, but it may be indicative of other things. Like errors,
// the ops team shouldn't be paged for errors, but a page might be
// triggered if a certain threshold of warnings is reached (which is
// typically much higher than errors). For example, repeated
// warnings might be a sign that the system is under attack.
// + INFO (2): informational message. This is a normal log message
// that is used to deliver information, such as recording
// requests. Ops teams are never paged for informational
// messages. This is the default log level.
// + DEBUG (1): debug-level message. These are only used during
// development or if a deployed system repeatedly sees abnormal
// errors.
//
// The numeric values indicate the priority of a given level.
//
// 2. The **actor** is used to specify which component is generating
// the log message. This could be the program name, or it could be
// a specific component inside the system.
//
// 3. The **event** is a short message indicating what happened. This is
// most like the traditional log message.
//
// 4. The **attributes** are an optional set of key-value string pairs that
// provide additional information.
//
// Additionally, each log message has an associated timestamp. For the
// text-based logs, this is "%FT%T%z"; for the binary logs, this is a
// 64-bit Unix timestamp. An example text-based timestamp might look like ::
//
// [2016-03-27T20:59:27-0700] [INFO] [actor:server event:request received] client=192.168.2.5 request-size=839
//
// Note that this is organised in a manner that facilitates parsing::
//
// /\[(\d{4}-\d{3}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4})\] \[(\w+\)]\) \[actor:(.+?) event:(.+?)\]/
//
// will cover the header:
//
// + ``$1`` contains the timestamp
// + ``$2`` contains the level
// + ``$3`` contains the actor
// + ``$4`` contains the event
type Logger interface { type Logger interface {
// SetLevel sets the minimum log level. // SetLevel sets the minimum log level.
SetLevel(Level) SetLevel(Level)
@@ -23,66 +84,6 @@ type Logger interface {
// Close gives the Logger the opportunity to perform any cleanup. // Close gives the Logger the opportunity to perform any cleanup.
Close() error Close() error
// Log messages consist of four components:
//
// 1. The **level** attaches a notion of priority to the log message.
// Several log levels are available:
//
// + FATAL (32): the system is in an unsuable state, and cannot
// continue to run. Most of the logging for this will cause the
// program to exit with an error code.
// + CRITICAL (16): critical conditions. The error, if uncorrected, is
// likely to cause a fatal condition shortly. An example is running
// out of disk space. This is something that the ops team should get
// paged for.
// + ERROR (8): error conditions. A single error doesn't require an
// ops team to be paged, but repeated errors should often trigger a
// page based on threshold triggers. An example is a network
// failure: it might be a transient failure (these do happen), but
// most of the time it's self-correcting.
// + WARNING (4): warning conditions. An example of this is a bad
// request sent to a server. This isn't an error on the part of the
// program, but it may be indicative of other things. Like errors,
// the ops team shouldn't be paged for errors, but a page might be
// triggered if a certain threshold of warnings is reached (which is
// typically much higher than errors). For example, repeated
// warnings might be a sign that the system is under attack.
// + INFO (2): informational message. This is a normal log message
// that is used to deliver information, such as recording
// requests. Ops teams are never paged for informational
// messages. This is the default log level.
// + DEBUG (1): debug-level message. These are only used during
// development or if a deployed system repeatedly sees abnormal
// errors.
//
// The numeric values indicate the priority of a given level.
//
// 2. The **actor** is used to specify which component is generating
// the log message. This could be the program name, or it could be
// a specific component inside the system.
//
// 3. The **event** is a short message indicating what happened. This is
// most like the traditional log message.
//
// 4. The **attributes** are an optional set of key-value string pairs that
// provide additional information.
//
// Additionally, each log message has an associated timestamp. For the
// text-based logs, this is "%FT%T%z"; for the binary logs, this is a
// 64-bit Unix timestamp. An example text-based timestamp might look like ::
//
// [2016-03-27T20:59:27-0700] [INFO] [actor:server event:request received] client=192.168.2.5 request-size=839
//
// Note that this is organised in a manner that facilitates parsing::
//
// /\[(\d{4}-\d{3}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4})\] \[(\w+\)]\) \[actor:(.+?) event:(.+?)\]/
//
// will cover the header:
//
// + ``$1`` contains the timestamp
// + ``$2`` contains the level
// + ``$3`` contains the actor
// + ``$4`` contains the event
Debug(actor, event string, attrs map[string]string) Debug(actor, event string, attrs map[string]string)
Info(actor, event string, attrs map[string]string) Info(actor, event string, attrs map[string]string)
Warn(actor, event string, attrs map[string]string) Warn(actor, event string, attrs map[string]string)

View File

@@ -9,8 +9,8 @@ go_library(
go_test( go_test(
name = "seekbuf_test", name = "seekbuf_test",
size = "small",
srcs = ["seekbuf_test.go"], srcs = ["seekbuf_test.go"],
embed = [":seekbuf"], embed = [":seekbuf"],
deps = ["//assert"], deps = ["//assert"],
size = "small"
) )

View File

@@ -1,4 +1,4 @@
// seekbuf implements a read-seekable buffer. // Package seekbuf implements a read-seekable buffer.
package seekbuf package seekbuf
import "io" import "io"

View File

@@ -1,9 +1,12 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "log", name = "syslog",
srcs = ["logger.go"], srcs = ["logger.go"],
importpath = "git.wntrmute.dev/kyle/kdhcp/log", importpath = "git.wntrmute.dev/kyle/goutils/syslog",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = ["@com_github_hashicorp_go_syslog//:go-syslog"], deps = [
"@com_github_davecgh_go_spew//spew",
"@com_github_hashicorp_go_syslog//:go-syslog",
],
) )

View File

@@ -1,4 +1,4 @@
// syslog is a syslog-type facility for logging. // Package syslog is a syslog-type facility for logging.
package syslog package syslog
import ( import (
@@ -7,6 +7,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/davecgh/go-spew/spew"
gsyslog "github.com/hashicorp/go-syslog" gsyslog "github.com/hashicorp/go-syslog"
) )
@@ -52,6 +53,12 @@ func (log *logger) println(p gsyslog.Priority, args ...interface{}) {
} }
} }
func (log *logger) spew(args ...interface{}) {
if log.p == gsyslog.LOG_DEBUG {
spew.Dump(args...)
}
}
func (log *logger) adjustPriority(level string) error { func (log *logger) adjustPriority(level string) error {
priority, ok := priorities[level] priority, ok := priorities[level]
if !ok { if !ok {
@@ -100,12 +107,12 @@ type Options struct {
// DefaultOptions returns a sane set of defaults for syslog, using the program // DefaultOptions returns a sane set of defaults for syslog, using the program
// name as the tag name. withSyslog controls whether logs should be sent to // name as the tag name. withSyslog controls whether logs should be sent to
// syslog, too. // syslog, too.
func DefaultOptions(tag string, withSyslog bool) { func DefaultOptions(tag string, withSyslog bool) *Options {
if tag == "" { if tag == "" {
tag = os.Args[0] tag = os.Args[0]
} }
return &DefaultOptions{ return &Options{
Level: "WARNING", Level: "WARNING",
Tag: tag, Tag: tag,
Facility: "daemon", Facility: "daemon",
@@ -113,15 +120,15 @@ func DefaultOptions(tag string, withSyslog bool) {
} }
} }
// DefaultDefaultOptions returns a sane set of debug defaults for syslog, // DefaultDebugOptions returns a sane set of debug defaults for syslog,
// using the program name as the tag name. withSyslog controls whether logs // using the program name as the tag name. withSyslog controls whether logs
// should be sent to syslog, too. // should be sent to syslog, too.
func DefaultDebugOptions(tag string, withSyslog bool) { func DefaultDebugOptions(tag string, withSyslog bool) *Options {
if tag == "" { if tag == "" {
tag = os.Args[0] tag = os.Args[0]
} }
return &DefaultOptions{ return &Options{
Level: "DEBUG", Level: "DEBUG",
Facility: "daemon", Facility: "daemon",
WriteSyslog: withSyslog, WriteSyslog: withSyslog,
@@ -131,16 +138,18 @@ func DefaultDebugOptions(tag string, withSyslog bool) {
func Setup(opts *Options) error { func Setup(opts *Options) error {
priority, ok := priorities[opts.Level] priority, ok := priorities[opts.Level]
if !ok { if !ok {
return fmt.Errorf("log: unknown priority %s", level) return fmt.Errorf("log: unknown priority %s", opts.Level)
} }
log.p = priority log.p = priority
if opts.WriteSyslog {
var err error var err error
log.l, err = gsyslog.NewLogger(priority, opts.Facility, opts.Tag) log.l, err = gsyslog.NewLogger(priority, opts.Facility, opts.Tag)
if err != nil { if err != nil {
return err return err
} }
}
return nil return nil
} }
@@ -252,6 +261,11 @@ func Fatalf(format string, args ...interface{}) {
os.Exit(1) os.Exit(1)
} }
// Spew will pretty print the args if the logger is set to DEBUG priority.
func Spew(args ...interface{}) {
log.spew(args...)
}
func ChangePriority(level string) error { func ChangePriority(level string) error {
return log.adjustPriority(level) return log.adjustPriority(level)
} }