1
0
mirror of https://github.com/rancher/os.git synced 2025-09-02 15:24:32 +00:00

Add defered syslog hook

Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
This commit is contained in:
Sven Dowideit
2017-07-12 14:18:02 +10:00
parent 43c620c4d8
commit bb20e96a98
27 changed files with 777 additions and 254 deletions

View File

@@ -93,7 +93,7 @@ func sysInit(c *config.CloudConfig) (*config.CloudConfig, error) {
}
func MainInit() {
log.InitLogger()
log.InitDeferedLogger()
log.Infof("MainInit() start")
if err := RunInit(); err != nil {
log.Fatal(err)
@@ -414,6 +414,8 @@ func RunInit() error {
return err
}
log.SyslogReady(true)
return pidOne()
}

View File

@@ -4,6 +4,8 @@ import (
"io"
"os"
"fmt"
"github.com/Sirupsen/logrus"
)
@@ -110,7 +112,15 @@ func WithFields(fields Fields) *logrus.Entry {
return appLog.WithFields(logrus.Fields(fields))
}
// InitLogger sets up Logging to log to /dev/kmsg and to Syslog
func InitLogger() {
InitDeferedLogger()
SyslogReady(false)
}
// InitDeferedLogger sets up logging to /dev/kmsg and to an internal buffer
// which is then written to Syslog when signaled by SyslogReady()
func InitDeferedLogger() {
if userHook != nil {
return // we've already initialised it
}
@@ -148,3 +158,17 @@ func InitLogger() {
thisLog.Debugf("START: %v in %s", os.Args, pwd)
}
// SyslogReady tells the storeing User hook to start writing to syslog
func SyslogReady(logHook bool) error {
if userHook != nil {
if logHook {
logrus.Infof("Starting Syslog Hook")
fmt.Fprintf(appLog.Out, "------------ Starting defered Syslog Hook (%s) ----------------\n", os.Args[0])
} else {
fmt.Fprintf(appLog.Out, "------------ Starting Syslog Hook (%s) ----------------\n", os.Args[0])
}
return userHook.LogSystemReady()
}
return nil
}

View File

@@ -2,32 +2,51 @@ package log
import (
"fmt"
"github.com/Sirupsen/logrus"
"log/syslog"
"os"
"github.com/Sirupsen/logrus"
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
)
// ShowuserlogHook writes all levels of logrus entries to a file for later analysis
// ShowuserlogHook stores all levels of logrus entries in memory until its told the RancherOS logging system is ready
// then it replays them to be logged
type ShowuserlogHook struct {
Level logrus.Level
Level logrus.Level
syslogHook *logrus_syslog.SyslogHook
storedEntries []*logrus.Entry
}
// NewShowuserlogHook creates a new hook for use
func NewShowuserlogHook(l logrus.Level) (*ShowuserlogHook, error) {
return &ShowuserlogHook{l}, nil
return &ShowuserlogHook{l, nil, []*logrus.Entry{}}, nil
}
// Fire is called by logrus when the Hook is active
func (hook *ShowuserlogHook) Fire(entry *logrus.Entry) error {
line, err := entry.String()
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
return err
}
if entry.Level <= hook.Level {
fmt.Printf("> %s", line)
fmt.Printf("SVEN %s", line)
}
if hook.syslogHook == nil {
hook.storedEntries = append(hook.storedEntries, entry)
} else {
err := hook.syslogHook.Fire(entry)
if err != nil {
fmt.Fprintf(os.Stderr, "LOGERR: Unable to write %s, %v", line, err)
return err
}
}
return nil
}
// Levels returns all log levels, so we can process them ourselves
func (hook *ShowuserlogHook) Levels() []logrus.Level {
return []logrus.Level{
logrus.DebugLevel,
@@ -38,3 +57,21 @@ func (hook *ShowuserlogHook) Levels() []logrus.Level {
logrus.PanicLevel,
}
}
// Set up Syslog Hook, and replay any stored entries.
func (hook *ShowuserlogHook) LogSystemReady() error {
if hook.syslogHook == nil {
h, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
if err != nil {
logrus.Debugf("error creating SyslogHook: %s", err)
return err
}
hook.syslogHook = h
for _, entry := range hook.storedEntries {
hook.syslogHook.Fire(entry)
}
}
return nil
}

View File

@@ -1,5 +1,5 @@
#!/bin/bash
set -e
set -ex
export ARCH=${ARCH:-"amd64"}
BASE=images

View File

@@ -1 +1 @@
APPEND rancher.autologin=tty1 rancher.autologin=ttyS0 rancher.autologin=ttyS1 console=tty0 console=ttyS0 console=ttyS1 printk.devkmsg=on ${APPEND}
APPEND rancher.debug=true rancher.autologin=tty1 rancher.autologin=ttyS0 rancher.autologin=ttyS1 console=tty0 console=ttyS0 console=ttyS1 printk.devkmsg=on ${APPEND}

View File

@@ -1,5 +1,5 @@
#!/bin/bash
set -e
set -ex
source $(dirname $0)/version

View File

@@ -1,5 +1,5 @@
#!/bin/bash
set -e
set -ex
cd $(dirname $0)/..

View File

@@ -1,6 +1,6 @@
github.com/Microsoft/go-winio v0.1.0
github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837
github.com/Sirupsen/logrus v0.11.0
github.com/Sirupsen/logrus v0.11.5
github.com/boltdb/bolt v1.2.0
github.com/cloudfoundry-incubator/candiedyaml 01cbc92901719f599b11f3a7e3b1768d7002b0bb https://github.com/rancher/candiedyaml
github.com/cloudfoundry/gosigar 3ed7c74352dae6dc00bdc8c74045375352e3ec05
@@ -53,7 +53,7 @@ github.com/vishvananda/netns 54f0e4339ce73702a0607f49922aaa1e749b418d
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
github.com/xeipuuv/gojsonschema ac452913faa25c08bb78810d3e6f88b8a39f8f25
github.com/SvenDowideit/cpuid 399bf479aea1edfbfe0b686c514631b511f44641
github.com/SvenDowideit/cpuid dfdb6dba69f48dd44c5cd831950be648f71162ca
golang.org/x/crypto 2f3083f6163ef51179ad42ed523a18c9a1141467
golang.org/x/net 991d3e32f76f19ee6d9caadb3a22eae8d23315f7 https://github.com/golang/net.git
golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git

View File

@@ -1,9 +1,7 @@
language: go
go:
- 1.3
- 1.4
- 1.5
- 1.6
- 1.7
- tip
install:
- go get -t ./...

View File

@@ -1,3 +1,31 @@
# 0.11.5
* feature: add writer and writerlevel to entry (#372)
# 0.11.4
* bug: fix undefined variable on solaris (#493)
# 0.11.3
* formatter: configure quoting of empty values (#484)
* formatter: configure quoting character (default is `"`) (#484)
* bug: fix not importing io correctly in non-linux environments (#481)
# 0.11.2
* bug: fix windows terminal detection (#476)
# 0.11.1
* bug: fix tty detection with custom out (#471)
# 0.11.0
* performance: Use bufferpool to allocate (#370)
* terminal: terminal detection for app-engine (#343)
* feature: exit handler (#375)
# 0.10.0
* feature: Add a test hook (#180)

View File

@@ -1,5 +1,11 @@
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus)
**Seeing weird case-sensitive problems?** See [this
issue](https://github.com/sirupsen/logrus/issues/451#issuecomment-264332021).
This change has been reverted. I apologize for causing this. I greatly
underestimated the impact this would have. Logrus strives for stability and
backwards compatibility and failed to provide that.
Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
yet stable (pre 1.0). Logrus itself is completely stable and has been used in
@@ -81,8 +87,9 @@ func init() {
// Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{})
// Output to stderr instead of stdout, could also be a file.
log.SetOutput(os.Stderr)
// Output to stdout instead of the default stderr
// Can be any io.Writer, see below for File example
log.SetOutput(os.Stdout)
// Only log the warning severity or above.
log.SetLevel(log.WarnLevel)
@@ -132,7 +139,15 @@ var log = logrus.New()
func main() {
// The API for setting attributes is a little different than the package level
// exported logger. See Godoc.
log.Out = os.Stderr
log.Out = os.Stdout
// You could set this to any `io.Writer` such as a file
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
// if err == nil {
// log.Out = file
// } else {
// log.Info("Failed to log to file, using default stderr")
// }
log.WithFields(logrus.Fields{
"animal": "walrus",
@@ -165,6 +180,20 @@ In general, with Logrus using any of the `printf`-family functions should be
seen as a hint you should add a field, however, you can still use the
`printf`-family functions with Logrus.
#### Default Fields
Often it's helpful to have fields _always_ attached to log statements in an
application or parts of one. For example, you may want to always log the
`request_id` and `user_ip` in the context of a request. Instead of writing
`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on
every line, you can create a `logrus.Entry` to pass around instead:
```go
requestLogger := log.WithFields(log.Fields{"request_id": request_id, user_ip: user_ip})
requestLogger.Info("something happened on that request") # will log request_id and user_ip
requestLogger.Warn("something not great happened")
```
#### Hooks
You can add hooks for logging levels. For example to send errors to an exception
@@ -200,40 +229,47 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
| Hook | Description |
| ----- | ----------- |
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) |
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) |
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) |
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
#### Level logging
@@ -309,8 +345,11 @@ The built-in logging formatters are:
without colors.
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
field to `true`. To force no colored output even if there is a TTY set the
`DisableColors` field to `true`
`DisableColors` field to `true`. For Windows, see
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
* `logrus.JSONFormatter`. Logs fields as JSON.
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
Third party logging formatters:
@@ -359,6 +398,18 @@ srv := http.Server{
Each line written to that writer will be printed the usual way, using formatters
and hooks. The level for those entries is `info`.
This means that we can override the standard library logger easily:
```go
logger := logrus.New()
logger.Formatter = &logrus.JSONFormatter{}
// Use logrus for standard log output
// Note that `log` here references stdlib's log
// Not logrus imported under the name `log`.
log.SetOutput(logger.Writer())
```
#### Rotation
Log rotation is not provided with Logrus. Log rotation should be done by an
@@ -407,7 +458,7 @@ logrus.RegisterExitHandler(handler)
...
```
#### Thread safty
#### Thread safety
By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.

View File

@@ -0,0 +1,39 @@
# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
## Usage
```go
import (
"log/syslog"
"github.com/Sirupsen/logrus"
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
)
func main() {
log := logrus.New()
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
if err == nil {
log.Hooks.Add(hook)
}
}
```
If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). Just assign empty string to the first two parameters of `NewSyslogHook`. It should look like the following.
```go
import (
"log/syslog"
"github.com/Sirupsen/logrus"
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
)
func main() {
log := logrus.New()
hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
if err == nil {
log.Hooks.Add(hook)
}
}
```

View File

@@ -0,0 +1,54 @@
// +build !windows,!nacl,!plan9
package logrus_syslog
import (
"fmt"
"github.com/Sirupsen/logrus"
"log/syslog"
"os"
)
// SyslogHook to send logs via syslog.
type SyslogHook struct {
Writer *syslog.Writer
SyslogNetwork string
SyslogRaddr string
}
// Creates a hook to be added to an instance of logger. This is called with
// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
// `if err == nil { log.Hooks.Add(hook) }`
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
w, err := syslog.Dial(network, raddr, priority, tag)
return &SyslogHook{w, network, raddr}, err
}
func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
line, err := entry.String()
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
return err
}
switch entry.Level {
case logrus.PanicLevel:
return hook.Writer.Crit(line)
case logrus.FatalLevel:
return hook.Writer.Crit(line)
case logrus.ErrorLevel:
return hook.Writer.Err(line)
case logrus.WarnLevel:
return hook.Writer.Warning(line)
case logrus.InfoLevel:
return hook.Writer.Info(line)
case logrus.DebugLevel:
return hook.Writer.Debug(line)
default:
return nil
}
}
func (hook *SyslogHook) Levels() []logrus.Level {
return logrus.AllLevels
}

View File

@@ -5,9 +5,40 @@ import (
"fmt"
)
type fieldKey string
type FieldMap map[fieldKey]string
const (
FieldKeyMsg = "msg"
FieldKeyLevel = "level"
FieldKeyTime = "time"
)
func (f FieldMap) resolve(key fieldKey) string {
if k, ok := f[key]; ok {
return k
}
return string(key)
}
type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string
// DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool
// FieldMap allows users to customize the names of keys for various fields.
// As an example:
// formatter := &JSONFormatter{
// FieldMap: FieldMap{
// FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level",
// FieldKeyLevel: "@message",
// },
// }
FieldMap FieldMap
}
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
@@ -29,9 +60,11 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
timestampFormat = DefaultTimestampFormat
}
data["time"] = entry.Time.Format(timestampFormat)
data["msg"] = entry.Message
data["level"] = entry.Level.String()
if !f.DisableTimestamp {
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
}
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
serialized, err := json.Marshal(data)
if err != nil {

View File

@@ -2,7 +2,9 @@
package logrus
import "io"
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool {
func IsTerminal(f io.Writer) bool {
return true
}

View File

@@ -9,14 +9,20 @@
package logrus
import (
"io"
"os"
"syscall"
"unsafe"
)
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool {
fd := syscall.Stderr
func IsTerminal(f io.Writer) bool {
var termios Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
switch v := f.(type) {
case *os.File:
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
default:
return false
}
}

View File

@@ -3,13 +3,19 @@
package logrus
import (
"io"
"os"
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal() bool {
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
return err == nil
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
_, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
return err == nil
default:
return false
}
}

View File

@@ -8,6 +8,8 @@
package logrus
import (
"io"
"os"
"syscall"
"unsafe"
)
@@ -19,9 +21,13 @@ var (
)
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool {
fd := syscall.Stderr
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
default:
return false
}
}

View File

@@ -3,9 +3,9 @@ package logrus
import (
"bytes"
"fmt"
"runtime"
"sort"
"strings"
"sync"
"time"
)
@@ -20,16 +20,10 @@ const (
var (
baseTimestamp time.Time
isTerminal bool
)
func init() {
baseTimestamp = time.Now()
isTerminal = IsTerminal()
}
func miniTS() int {
return int(time.Since(baseTimestamp) / time.Second)
}
type TextFormatter struct {
@@ -54,11 +48,32 @@ type TextFormatter struct {
// that log extremely frequently and don't use the JSON formatter this may not
// be desired.
DisableSorting bool
// QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool
// QuoteCharacter can be set to the override the default quoting character "
// with something else. For example: ', or `.
QuoteCharacter string
// Whether the logger's out is to a terminal
isTerminal bool
sync.Once
}
func (f *TextFormatter) init(entry *Entry) {
if len(f.QuoteCharacter) == 0 {
f.QuoteCharacter = "\""
}
if entry.Logger != nil {
f.isTerminal = IsTerminal(entry.Logger.Out)
}
}
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var b *bytes.Buffer
var keys []string = make([]string, 0, len(entry.Data))
keys := make([]string, 0, len(entry.Data))
for k := range entry.Data {
keys = append(keys, k)
}
@@ -74,8 +89,9 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
prefixFieldClashes(entry.Data)
isColorTerminal := isTerminal && (runtime.GOOS != "windows")
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
f.Do(func() { f.init(entry) })
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
@@ -115,8 +131,10 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
levelText := strings.ToUpper(entry.Level.String())[0:4]
if !f.FullTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
if f.DisableTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
} else if !f.FullTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
} else {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
}
@@ -127,7 +145,10 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
}
}
func needsQuoting(text string) bool {
func (f *TextFormatter) needsQuoting(text string) bool {
if f.QuoteEmptyFields && len(text) == 0 {
return true
}
for _, ch := range text {
if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
@@ -150,17 +171,17 @@ func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interf
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
switch value := value.(type) {
case string:
if !needsQuoting(value) {
if !f.needsQuoting(value) {
b.WriteString(value)
} else {
fmt.Fprintf(b, "%q", value)
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
}
case error:
errmsg := value.Error()
if !needsQuoting(errmsg) {
if !f.needsQuoting(errmsg) {
b.WriteString(errmsg)
} else {
fmt.Fprintf(b, "%q", errmsg)
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
}
default:
fmt.Fprint(b, value)

View File

@@ -11,39 +11,48 @@ func (logger *Logger) Writer() *io.PipeWriter {
}
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
return NewEntry(logger).WriterLevel(level)
}
func (entry *Entry) Writer() *io.PipeWriter {
return entry.WriterLevel(InfoLevel)
}
func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
reader, writer := io.Pipe()
var printFunc func(args ...interface{})
switch level {
case DebugLevel:
printFunc = logger.Debug
printFunc = entry.Debug
case InfoLevel:
printFunc = logger.Info
printFunc = entry.Info
case WarnLevel:
printFunc = logger.Warn
printFunc = entry.Warn
case ErrorLevel:
printFunc = logger.Error
printFunc = entry.Error
case FatalLevel:
printFunc = logger.Fatal
printFunc = entry.Fatal
case PanicLevel:
printFunc = logger.Panic
printFunc = entry.Panic
default:
printFunc = logger.Print
printFunc = entry.Print
}
go logger.writerScanner(reader, printFunc)
go entry.writerScanner(reader, printFunc)
runtime.SetFinalizer(writer, writerFinalizer)
return writer
}
func (logger *Logger) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
printFunc(scanner.Text())
}
if err := scanner.Err(); err != nil {
logger.Errorf("Error while reading from Writer: %s", err)
entry.Errorf("Error while reading from Writer: %s", err)
}
reader.Close()
}

View File

@@ -12,7 +12,6 @@ package cpuid
import (
"strings"
"unsafe"
)
// Vendor is a representation of a CPU vendor.
@@ -565,9 +564,8 @@ func isHypervisorActive() bool {
}
func getHypervisorCpuid(ax uint32) string {
a, b, c, d := cpuid(ax)
var info [4]uint32 = [4]uint32{a, b, c, d}
name := strings.TrimRight(string((*[12]byte)(unsafe.Pointer(&info[1]))[:]), "\000")
_, b, c, d := cpuid(ax)
name := strings.TrimRight(string(valAsString(b, c, d)), "\000")
return name
}
@@ -584,10 +582,7 @@ func hypervisorName() string {
// return hv
//}
if hv := getHypervisorCpuid(0x40000000); hv != "" {
return hv
}
return ""
return getHypervisorCpuid(0x40000000)
}
// https://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID

View File

@@ -1,4 +1,4 @@
// Copyright 2016 VMware, Inc. All Rights Reserved.
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
package bdoor
const (
BackdoorMagic = uint64(0x564D5868)
BackdoorPort = uint16(0x5658)
BackdoorHighBWPort = uint16(0x5659)
@@ -26,109 +25,80 @@ const (
CommandFlagCookie = uint32(0x80000000)
)
type BackdoorProto struct {
// typedef union {
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// size_t size; /* Register bx. */
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } in;
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// DECLARE_REG_NAMED_STRUCT(bx);
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } out;
// } proto;
AX, BX, CX, DX, SI, DI, BP UInt64
size uint32
}
func bdoor_inout(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_hbout(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_hbin(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_inout_test(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func (p *BackdoorProto) InOut() *BackdoorProto {
p.DX.Low.Low = BackdoorPort
p.AX.SetQuad(BackdoorMagic)
p.DX.AsUInt32().Low = BackdoorPort
p.AX.SetValue(BackdoorMagic)
retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_inout(
p.AX.Quad(),
p.BX.Quad(),
p.CX.Quad(),
p.DX.Quad(),
p.SI.Quad(),
p.DI.Quad(),
p.BP.Quad(),
p.AX.Value(),
p.BX.Value(),
p.CX.Value(),
p.DX.Value(),
p.SI.Value(),
p.DI.Value(),
p.BP.Value(),
)
ret := &BackdoorProto{}
ret.AX.SetQuad(retax)
ret.BX.SetQuad(retbx)
ret.CX.SetQuad(retcx)
ret.DX.SetQuad(retdx)
ret.SI.SetQuad(retsi)
ret.DI.SetQuad(retdi)
ret.BP.SetQuad(retbp)
ret.AX.SetValue(retax)
ret.BX.SetValue(retbx)
ret.CX.SetValue(retcx)
ret.DX.SetValue(retdx)
ret.SI.SetValue(retsi)
ret.DI.SetValue(retdi)
ret.BP.SetValue(retbp)
return ret
}
func (p *BackdoorProto) HighBandwidthOut() *BackdoorProto {
p.DX.Low.Low = BackdoorHighBWPort
p.AX.SetQuad(BackdoorMagic)
p.DX.AsUInt32().Low = BackdoorHighBWPort
p.AX.SetValue(BackdoorMagic)
retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_hbout(
p.AX.Quad(),
p.BX.Quad(),
p.CX.Quad(),
p.DX.Quad(),
p.SI.Quad(),
p.DI.Quad(),
p.BP.Quad(),
p.AX.Value(),
p.BX.Value(),
p.CX.Value(),
p.DX.Value(),
p.SI.Value(),
p.DI.Value(),
p.BP.Value(),
)
ret := &BackdoorProto{}
ret.AX.SetQuad(retax)
ret.BX.SetQuad(retbx)
ret.CX.SetQuad(retcx)
ret.DX.SetQuad(retdx)
ret.SI.SetQuad(retsi)
ret.DI.SetQuad(retdi)
ret.BP.SetQuad(retbp)
ret.AX.SetValue(retax)
ret.BX.SetValue(retbx)
ret.CX.SetValue(retcx)
ret.DX.SetValue(retdx)
ret.SI.SetValue(retsi)
ret.DI.SetValue(retdi)
ret.BP.SetValue(retbp)
return ret
}
func (p *BackdoorProto) HighBandwidthIn() *BackdoorProto {
p.DX.Low.Low = BackdoorHighBWPort
p.AX.SetQuad(BackdoorMagic)
p.DX.AsUInt32().Low = BackdoorHighBWPort
p.AX.SetValue(BackdoorMagic)
retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_hbin(
p.AX.Quad(),
p.BX.Quad(),
p.CX.Quad(),
p.DX.Quad(),
p.SI.Quad(),
p.DI.Quad(),
p.BP.Quad(),
p.AX.Value(),
p.BX.Value(),
p.CX.Value(),
p.DX.Value(),
p.SI.Value(),
p.DI.Value(),
p.BP.Value(),
)
ret := &BackdoorProto{}
ret.AX.SetQuad(retax)
ret.BX.SetQuad(retbx)
ret.CX.SetQuad(retcx)
ret.DX.SetQuad(retdx)
ret.SI.SetQuad(retsi)
ret.DI.SetQuad(retdi)
ret.BP.SetQuad(retbp)
ret.AX.SetValue(retax)
ret.BX.SetValue(retbx)
ret.CX.SetValue(retcx)
ret.DX.SetValue(retdx)
ret.SI.SetValue(retsi)
ret.DI.SetValue(retdi)
ret.BP.SetValue(retbp)
return ret
}

View File

@@ -0,0 +1,48 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bdoor
const (
BackdoorMagic = uint32(0x564D5868)
)
type BackdoorProto struct {
// typedef union {
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// size_t size; /* Register bx. */
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } in;
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// DECLARE_REG_NAMED_STRUCT(bx);
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } out;
// } proto;
AX, BX, CX, DX, SI, DI, BP UInt32
size uint32
}
func bdoor_inout(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
func bdoor_hbout(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
func bdoor_hbin(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
func bdoor_inout_test(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)

View File

@@ -0,0 +1,112 @@
#include "textflag.h"
// Doc of the golang plan9 assembler
// http://p9.nyx.link/labs/sys/doc/asm.html
//
// A good primer of how to write golang with some plan9 flavored assembly
// http://www.doxsey.net/blog/go-and-assembly
//
// Some x86 references
// http://www.eecg.toronto.edu/~amza/www.mindsec.com/files/x86regs.html
// https://cseweb.ucsd.edu/classes/sp10/cse141/pdf/02/S01_x86_64.key.pdf
// https://en.wikibooks.org/wiki/X86_Assembly/Other_Instructions
//
// (This one is invaluable. Has a working example of how a standard function
// call looks on the stack with the associated assembly.)
// https://www.recurse.com/blog/7-understanding-c-by-learning-assembly
//
// Reference with raw form of the Opcode
// http://x86.renejeschke.de/html/file_module_x86_id_139.html
//
// Massive x86_64 reference
// http://ref.x86asm.net/coder64.html#xED
//
// Adding instructions to the go assembler
// https://blog.klauspost.com/adding-unsupported-instructions-in-golang-assembler/
//
// Backdoor commands
// https://sites.google.com/site/chitchatvmback/backdoor
// func bdoor_inout(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
TEXT ·bdoor_inout(SB), NOSPLIT|WRAPPER, $0
MOVL ax+0(FP), AX
MOVL bx+4(FP), BX
MOVL cx+8(FP), CX
MOVL dx+12(FP), DX
MOVL si+16(FP), SI
MOVL di+20(FP), DI
MOVL bp+24(FP), BP
// IN to DX from EAX
INL
MOVL AX, retax+28(FP)
MOVL BX, retbx+32(FP)
MOVL CX, retcx+36(FP)
MOVL DX, retdx+40(FP)
MOVL SI, retsi+44(FP)
MOVL DI, retdi+48(FP)
MOVL BP, retbp+52(FP)
RET
// func bdoor_hbout(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
TEXT ·bdoor_hbout(SB), NOSPLIT|WRAPPER, $0
MOVL ax+0(FP), AX
MOVL bx+4(FP), BX
MOVL cx+8(FP), CX
MOVL dx+12(FP), DX
MOVL si+16(FP), SI
MOVL di+20(FP), DI
MOVL bp+24(FP), BP
CLD; REP; OUTSB
MOVL AX, retax+28(FP)
MOVL BX, retbx+32(FP)
MOVL CX, retcx+36(FP)
MOVL DX, retdx+40(FP)
MOVL SI, retsi+44(FP)
MOVL DI, retdi+48(FP)
MOVL BP, retbp+52(FP)
RET
// func bdoor_hbin(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
TEXT ·bdoor_hbin(SB), NOSPLIT|WRAPPER, $0
MOVL ax+0(FP), AX
MOVL bx+4(FP), BX
MOVL cx+8(FP), CX
MOVL dx+12(FP), DX
MOVL si+16(FP), SI
MOVL di+20(FP), DI
MOVL bp+24(FP), BP
CLD; REP; INSB
MOVL AX, retax+28(FP)
MOVL BX, retbx+32(FP)
MOVL CX, retcx+40(FP)
MOVL DX, retdx+44(FP)
MOVL SI, retsi+48(FP)
MOVL DI, retdi+52(FP)
MOVL BP, retbp+56(FP)
RET
// func bdoor_inout_test(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
TEXT ·bdoor_inout_test(SB), NOSPLIT|WRAPPER, $0
MOVL ax+0(FP), AX
MOVL bx+4(FP), BX
MOVL cx+8(FP), CX
MOVL dx+12(FP), DX
MOVL si+16(FP), SI
MOVL di+20(FP), DI
MOVL bp+24(FP), BP
MOVL AX, retax+28(FP)
MOVL BX, retbx+32(FP)
MOVL CX, retcx+36(FP)
MOVL DX, retdx+40(FP)
MOVL SI, retsi+44(FP)
MOVL DI, retdi+48(FP)
MOVL BP, retbp+52(FP)
RET

View File

@@ -0,0 +1,48 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bdoor
const (
BackdoorMagic = uint64(0x564D5868)
)
type BackdoorProto struct {
// typedef union {
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// size_t size; /* Register bx. */
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } in;
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// DECLARE_REG_NAMED_STRUCT(bx);
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } out;
// } proto;
AX, BX, CX, DX, SI, DI, BP UInt64
size uint32
}
func bdoor_inout(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_hbout(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_hbin(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_inout_test(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)

View File

@@ -1,4 +1,4 @@
// Copyright 2016 VMware, Inc. All Rights Reserved.
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,6 +14,8 @@
package bdoor
import "unsafe"
type UInt32 struct {
High uint16
Low uint16
@@ -28,6 +30,22 @@ func (u *UInt32) SetWord(w uint32) {
u.Low = uint16(w)
}
func (u *UInt32) AsUInt32() *UInt32 {
return u
}
func (u *UInt32) Value() uint32 {
return u.Word()
}
func (u *UInt32) SetValue(val uint32) {
u.SetWord(val)
}
func (u *UInt32) SetPointer(p unsafe.Pointer) {
u.SetWord(uint32(uintptr(p)))
}
type UInt64 struct {
High UInt32
Low UInt32
@@ -41,3 +59,19 @@ func (u *UInt64) SetQuad(w uint64) {
u.High.SetWord(uint32(w >> 32))
u.Low.SetWord(uint32(w))
}
func (u *UInt64) AsUInt32() *UInt32 {
return &u.Low
}
func (u *UInt64) Value() uint64 {
return u.Quad()
}
func (u *UInt64) SetValue(val uint64) {
u.SetQuad(val)
}
func (u *UInt64) SetPointer(p unsafe.Pointer) {
u.SetQuad(uint64(uintptr(p)))
}

View File

@@ -1,4 +1,4 @@
// Copyright 2016 VMware, Inc. All Rights Reserved.
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -66,12 +66,12 @@ func NewChannel(proto uint32) (*Channel, error) {
retry:
bp := &bdoor.BackdoorProto{}
bp.BX.Low.SetWord(proto | flags)
bp.CX.Low.High = messageTypeOpen
bp.CX.Low.Low = bdoor.CommandMessage
bp.BX.AsUInt32().SetWord(proto | flags)
bp.CX.AsUInt32().High = messageTypeOpen
bp.CX.AsUInt32().Low = bdoor.CommandMessage
out := bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 {
if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
if flags != 0 {
flags = 0
goto retry
@@ -82,9 +82,9 @@ retry:
}
ch := &Channel{}
ch.id = out.DX.Low.High
ch.cookie.High.SetWord(out.SI.Low.Word())
ch.cookie.Low.SetWord(out.DI.Low.Word())
ch.id = out.DX.AsUInt32().High
ch.cookie.High.SetWord(out.SI.AsUInt32().Word())
ch.cookie.Low.SetWord(out.DI.AsUInt32().Word())
Debugf("Opened channel %d", ch.id)
return ch, nil
@@ -93,15 +93,15 @@ retry:
func (c *Channel) Close() error {
bp := &bdoor.BackdoorProto{}
bp.CX.Low.High = messageTypeClose
bp.CX.Low.Low = bdoor.CommandMessage
bp.CX.AsUInt32().High = messageTypeClose
bp.CX.AsUInt32().Low = bdoor.CommandMessage
bp.DX.Low.High = c.id
bp.SI.Low.SetWord(c.cookie.High.Word())
bp.DI.Low.SetWord(c.cookie.Low.Word())
bp.DX.AsUInt32().High = c.id
bp.SI.AsUInt32().SetWord(c.cookie.High.Word())
bp.DI.AsUInt32().SetWord(c.cookie.Low.Word())
out := bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 {
if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
Errorf("Message: Unable to close communication channel %d", c.id)
return ErrChannelClose
}
@@ -113,18 +113,18 @@ func (c *Channel) Close() error {
func (c *Channel) Send(buf []byte) error {
retry:
bp := &bdoor.BackdoorProto{}
bp.CX.Low.High = messageTypeSendSize
bp.CX.Low.Low = bdoor.CommandMessage
bp.CX.AsUInt32().High = messageTypeSendSize
bp.CX.AsUInt32().Low = bdoor.CommandMessage
bp.DX.Low.High = c.id
bp.SI.Low.SetWord(c.cookie.High.Word())
bp.DI.Low.SetWord(c.cookie.Low.Word())
bp.DX.AsUInt32().High = c.id
bp.SI.AsUInt32().SetWord(c.cookie.High.Word())
bp.DI.AsUInt32().SetWord(c.cookie.Low.Word())
bp.BX.Low.SetWord(uint32(len(buf)))
bp.BX.AsUInt32().SetWord(uint32(len(buf)))
// send the size
out := bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 {
if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
Errorf("Message: Unable to send a message over the communication channel %d", c.id)
return ErrRpciSend
}
@@ -134,20 +134,20 @@ retry:
return nil
}
if !c.forceLowBW && (out.CX.Low.High&messageStatusHighBW) == messageStatusHighBW {
if !c.forceLowBW && (out.CX.AsUInt32().High&messageStatusHighBW) == messageStatusHighBW {
hbbp := &bdoor.BackdoorProto{}
hbbp.BX.Low.Low = bdoor.CommandHighBWMessage
hbbp.BX.Low.High = messageStatusSuccess
hbbp.DX.Low.High = c.id
hbbp.BP.Low.SetWord(c.cookie.High.Word())
hbbp.DI.Low.SetWord(c.cookie.Low.Word())
hbbp.CX.Low.SetWord(uint32(len(buf)))
hbbp.SI.SetQuad(uint64(uintptr(unsafe.Pointer(&buf[0]))))
hbbp.BX.AsUInt32().Low = bdoor.CommandHighBWMessage
hbbp.BX.AsUInt32().High = messageStatusSuccess
hbbp.DX.AsUInt32().High = c.id
hbbp.BP.AsUInt32().SetWord(c.cookie.High.Word())
hbbp.DI.AsUInt32().SetWord(c.cookie.Low.Word())
hbbp.CX.AsUInt32().SetWord(uint32(len(buf)))
hbbp.SI.SetPointer(unsafe.Pointer(&buf[0]))
out := hbbp.HighBandwidthOut()
if (out.BX.Low.High & messageStatusSuccess) == 0 {
if (out.BX.Low.High & messageStatusCheckPoint) != 0 {
if (out.BX.AsUInt32().High & messageStatusSuccess) == 0 {
if (out.BX.AsUInt32().High & messageStatusCheckPoint) != 0 {
Debugf("A checkpoint occurred. Retrying the operation")
goto retry
}
@@ -156,7 +156,7 @@ retry:
return ErrRpciSend
}
} else {
bp.CX.Low.High = messageTypeSendPayload
bp.CX.AsUInt32().High = messageTypeSendPayload
bbuf := bytes.NewBuffer(buf)
for {
@@ -169,17 +169,17 @@ retry:
Debugf("sending %q over %d", string(words), c.id)
switch len(words) {
case 3:
bp.BX.Low.SetWord(binary.LittleEndian.Uint32([]byte{0x0, words[2], words[1], words[0]}))
bp.BX.AsUInt32().SetWord(binary.LittleEndian.Uint32([]byte{0x0, words[2], words[1], words[0]}))
case 2:
bp.BX.Low.SetWord(uint32(binary.LittleEndian.Uint16(words)))
bp.BX.AsUInt32().SetWord(uint32(binary.LittleEndian.Uint16(words)))
case 1:
bp.BX.Low.SetWord(uint32(words[0]))
bp.BX.AsUInt32().SetWord(uint32(words[0]))
default:
bp.BX.Low.SetWord(binary.LittleEndian.Uint32(words))
bp.BX.AsUInt32().SetWord(binary.LittleEndian.Uint32(words))
}
out = bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 {
if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
Errorf("Message: Unable to send a message over the communication channel %d", c.id)
return ErrRpciSend
}
@@ -193,50 +193,50 @@ func (c *Channel) Receive() ([]byte, error) {
retry:
var err error
bp := &bdoor.BackdoorProto{}
bp.CX.Low.High = messageTypeReceiveSize
bp.CX.Low.Low = bdoor.CommandMessage
bp.CX.AsUInt32().High = messageTypeReceiveSize
bp.CX.AsUInt32().Low = bdoor.CommandMessage
bp.DX.Low.High = c.id
bp.SI.Low.SetWord(c.cookie.High.Word())
bp.DI.Low.SetWord(c.cookie.Low.Word())
bp.DX.AsUInt32().High = c.id
bp.SI.AsUInt32().SetWord(c.cookie.High.Word())
bp.DI.AsUInt32().SetWord(c.cookie.Low.Word())
out := bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 {
if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
Errorf("Message: Unable to poll for messages over the communication channel %d", c.id)
return nil, ErrRpciReceive
}
if (out.CX.Low.High & messageStatusDoRecieve) == 0 {
if (out.CX.AsUInt32().High & messageStatusDoRecieve) == 0 {
Debugf("No message to retrieve")
return nil, nil
}
// Receive the size.
if out.DX.Low.High != messageTypeSendSize {
if out.DX.AsUInt32().High != messageTypeSendSize {
Errorf("Message: Protocol error. Expected a MESSAGE_TYPE_SENDSIZE request from vmware")
return nil, ErrRpciReceive
}
size := out.BX.Quad()
size := out.BX.Value()
var buf []byte
if size != 0 {
if !c.forceLowBW && (out.CX.Low.High&messageStatusHighBW == messageStatusHighBW) {
if !c.forceLowBW && (out.CX.AsUInt32().High&messageStatusHighBW == messageStatusHighBW) {
buf = make([]byte, size)
hbbp := &bdoor.BackdoorProto{}
hbbp.BX.Low.Low = bdoor.CommandHighBWMessage
hbbp.BX.Low.High = messageStatusSuccess
hbbp.DX.Low.High = c.id
hbbp.SI.Low.SetWord(c.cookie.High.Word())
hbbp.BP.Low.SetWord(c.cookie.Low.Word())
hbbp.CX.Low.SetWord(uint32(len(buf)))
hbbp.DI.SetQuad(uint64(uintptr(unsafe.Pointer(&buf[0]))))
hbbp.BX.AsUInt32().Low = bdoor.CommandHighBWMessage
hbbp.BX.AsUInt32().High = messageStatusSuccess
hbbp.DX.AsUInt32().High = c.id
hbbp.SI.AsUInt32().SetWord(c.cookie.High.Word())
hbbp.BP.AsUInt32().SetWord(c.cookie.Low.Word())
hbbp.CX.AsUInt32().SetWord(uint32(len(buf)))
hbbp.DI.SetPointer(unsafe.Pointer(&buf[0]))
out := hbbp.HighBandwidthIn()
if (out.BX.Low.High & messageStatusSuccess) == 0 {
if (out.BX.AsUInt32().High & messageStatusSuccess) == 0 {
Errorf("Message: Unable to send a message over the communication channel %d", c.id)
c.reply(messageTypeReceivePayload, messageStatusFail)
return nil, ErrRpciReceive
@@ -249,12 +249,12 @@ retry:
break
}
bp.CX.Low.High = messageTypeReceivePayload
bp.BX.Low.Low = messageStatusSuccess
bp.CX.AsUInt32().High = messageTypeReceivePayload
bp.BX.AsUInt32().Low = messageStatusSuccess
out = bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 {
if (out.CX.Low.High & messageStatusCheckPoint) != 0 {
if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
if (out.CX.AsUInt32().High & messageStatusCheckPoint) != 0 {
Debugf("A checkpoint occurred. Retrying the operation")
goto retry
}
@@ -264,34 +264,34 @@ retry:
return nil, ErrRpciReceive
}
if out.DX.Low.High != messageTypeSendPayload {
if out.DX.AsUInt32().High != messageTypeSendPayload {
Errorf("Message: Protocol error. Expected a MESSAGE_TYPE_SENDPAYLOAD from vmware")
c.reply(messageTypeReceivePayload, messageStatusFail)
return nil, ErrRpciReceive
}
Debugf("Received %#v", out.BX.Low.Word())
Debugf("Received %#v", out.BX.AsUInt32().Word())
switch size {
case 1:
err = binary.Write(b, binary.LittleEndian, uint8(out.BX.Low.Low))
err = binary.Write(b, binary.LittleEndian, uint8(out.BX.AsUInt32().Low))
size = size - 1
case 2:
err = binary.Write(b, binary.LittleEndian, uint16(out.BX.Low.Low))
err = binary.Write(b, binary.LittleEndian, uint16(out.BX.AsUInt32().Low))
size = size - 2
case 3:
err = binary.Write(b, binary.LittleEndian, uint16(out.BX.Low.Low))
err = binary.Write(b, binary.LittleEndian, uint16(out.BX.AsUInt32().Low))
if err != nil {
c.reply(messageTypeReceivePayload, messageStatusFail)
return nil, ErrRpciReceive
}
err = binary.Write(b, binary.LittleEndian, uint8(out.BX.Low.High))
err = binary.Write(b, binary.LittleEndian, uint8(out.BX.AsUInt32().High))
size = size - 3
default:
err = binary.Write(b, binary.LittleEndian, out.BX.Low.Word())
err = binary.Write(b, binary.LittleEndian, out.BX.AsUInt32().Word())
size = size - 4
}
@@ -314,17 +314,17 @@ retry:
func (c *Channel) reply(messageType, messageStatus uint16) {
bp := &bdoor.BackdoorProto{}
bp.BX.Low.Low = messageStatus
bp.CX.Low.High = messageType
bp.CX.Low.Low = bdoor.CommandMessage
bp.DX.Low.High = c.id
bp.SI.Low.SetWord(c.cookie.High.Word())
bp.DI.Low.SetWord(c.cookie.Low.Word())
bp.BX.AsUInt32().Low = messageStatus
bp.CX.AsUInt32().High = messageType
bp.CX.AsUInt32().Low = bdoor.CommandMessage
bp.DX.AsUInt32().High = c.id
bp.SI.AsUInt32().SetWord(c.cookie.High.Word())
bp.DI.AsUInt32().SetWord(c.cookie.Low.Word())
out := bp.InOut()
/* OUT: Status */
if (out.CX.Low.High & messageStatusSuccess) == 0 {
if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
if messageStatus == messageStatusSuccess {
Errorf("reply Message: Unable to send a message over the communication channel %d", c.id)
} else {