pax_global_header00006660000000000000000000000064141606152530014515gustar00rootroot0000000000000052 comment=5538e904aeb515c10a624da620581bdf420d4b8a fluent-logger-golang-1.9.0/000077500000000000000000000000001416061525300155435ustar00rootroot00000000000000fluent-logger-golang-1.9.0/.github/000077500000000000000000000000001416061525300171035ustar00rootroot00000000000000fluent-logger-golang-1.9.0/.github/workflows/000077500000000000000000000000001416061525300211405ustar00rootroot00000000000000fluent-logger-golang-1.9.0/.github/workflows/ci.yaml000066400000000000000000000015341416061525300224220ustar00rootroot00000000000000name: ci on: pull_request: branches: '*' push: branches: - master - main - 'release-*' jobs: test: strategy: matrix: os: [ubuntu, macos, windows] golang: ['1.13', '1.16', '1.17'] # currently, we cannot run non-x86_64 machines on Github Actions cloud env. runs-on: ${{ matrix.os }}-latest name: CI golang ${{ matrix.golang }} on ${{ matrix.os }} steps: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: go-version: ${{ matrix.golang }} - name: Change GO11MODULES run: go env -w GO111MODULE=auto - name: Install requirements run: | go get github.com/bmizerany/assert go get github.com/philhofer/fwd go get github.com/tinylib/msgp - name: Test run: go test -v ./fluent fluent-logger-golang-1.9.0/.gitignore000066400000000000000000000000451416061525300175320ustar00rootroot00000000000000.DS_Store *~ .project .settings .ideafluent-logger-golang-1.9.0/CHANGELOG.md000066400000000000000000000050751416061525300173630ustar00rootroot00000000000000# CHANGELOG ## 1.9.0 New features * Add a new option `AsyncReconnectInterval` for periodic connection refresh. #111 Contributions to this release * Conor Evans ## 1.8.0 New features * Support logging over secure connections using TLS. #107 Changes * Change `Fluent.Post()` to return an error after connection close. #105 Contributions to this release * Love Sharma * Fujimoto Seiji ## 1.7.0 * Update connection management to stop logger during connection failures ## 1.6.3 * Fix not to panic when accessing unexported struct fields ## 1.6.2 * Add `AsyncResultCallback` to allow users to handle errors when using asynchronous message sending. ## 1.6.1 * Add another fix for `Close` called twice in Async ## 1.6.0 * Add support for `ppc64le` * Fix unexpected behaviors&panic around `Close` ## 1.5.0 * Add `ForceStopAsyncSend` to stop asynchronous message transferring immediately when `close()` called * Fix to lock connections only when needed * Fix a bug to panic for closing nil connection ## 1.4.0 * Add `RequestAck` to enable at-least-once message transferring * Add `Async` option to update sending message in asynchronous way * Deprecate `AsyncConnect` (Use `Async` instead) ## 1.3.0 * Add `SubSecondPrecision` option to handle Fluentd v0.14 (and v1) sub-second EventTime (default: false) * Add `WriteTimeout` option * Fix API of `Post` to accept `msgp.Marshaler` objects for better performance ## 1.2.1 * Fix a bug not to reconnect to destination twice or more * Fix to connect on background goroutine in async mode ## 1.2.0 * Add `MarshalAsJSON` feature for `message` objects which can be marshaled as JSON * Fix a bug to panic for destination system outage ## 1.1.0 * Add support for unix domain socket * Add asynchronous client creation ## 1.0.0 * Fix API of `Post` and `PostWithTime` to return error when encoding * Add argument checks to get `map` with string keys and `struct` only * Logger refers tags (`msg` or `codec`) of fields of struct ## 0.6.0 * Change dependency from ugorji/go/codec to tinylib/msgp * Add `PostRawData` method to post pre-encoded data to servers ## 0.5.1 * Lock when writing pending buffers (Thanks @eagletmt) ## 0.5.0 * Add TagPrefix in Config (Thanks @hotchpotch) ## 0.4.4 * Fixes runtime error of close function.(Thanks @y-matsuwitter) ## 0.4.3 * Added method PostWithTime(Thanks [@choplin]) ## 0.4.2 * Use sync.Mutex * Fix BufferLimit comparison * Export toMsgpack function to utils.go ## 0.4.1 * Remove unused fmt.Println ## 0.4.0 * Update msgpack library ("github.com/ugorji/go-msgpack" -> "github.com/ugorji/go/codec") fluent-logger-golang-1.9.0/LICENSE000066400000000000000000000261361416061525300165600ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. fluent-logger-golang-1.9.0/README.md000066400000000000000000000127541416061525300170330ustar00rootroot00000000000000fluent-logger-golang ==== [![Build Status](https://github.com/fluent/fluent-logger-golang/actions/workflows/ci.yaml/badge.svg?branch=master)](https://github.com/fluent/fluent-logger-golang/actions) [![GoDoc](https://godoc.org/github.com/fluent/fluent-logger-golang/fluent?status.svg)](https://godoc.org/github.com/fluent/fluent-logger-golang/fluent) ## A structured event logger for Fluentd (Golang) ## How to install ``` go get github.com/fluent/fluent-logger-golang/fluent ``` ## Usage Install the package with `go get` and use `import` to include it in your project. ``` import "github.com/fluent/fluent-logger-golang/fluent" ``` ## Example ```go package main import ( "github.com/fluent/fluent-logger-golang/fluent" "fmt" //"time" ) func main() { logger, err := fluent.New(fluent.Config{}) if err != nil { fmt.Println(err) } defer logger.Close() tag := "myapp.access" var data = map[string]string{ "foo": "bar", "hoge": "hoge", } error := logger.Post(tag, data) // error := logger.PostWithTime(tag, time.Now(), data) if error != nil { panic(error) } } ``` `data` must be a value like `map[string]literal`, `map[string]interface{}`, `struct` or [`msgp.Marshaler`](http://godoc.org/github.com/tinylib/msgp/msgp#Marshaler). Logger refers tags `msg` or `codec` of each fields of structs. ## Setting config values ```go f := fluent.New(fluent.Config{FluentPort: 80, FluentHost: "example.com"}) ``` ### FluentNetwork Specify the network protocol. The supported values are: * "tcp" (use `FluentHost` and `FluentPort`) * "tls" (use`FluentHost` and `FluentPort`) * "unix" (use `FluentSocketPath`) The default is "tcp". ### FluentHost Specify a hostname or IP address as a string for the destination of the "tcp" protocol. The default is "127.0.0.1". ### FluentPort Specify the TCP port of the destination. The default is 24224. ### FluentSocketPath Specify the unix socket path when `FluentNetwork` is "unix". ### Timeout Set the timeout value of `time.Duration` to connect to the destination. The default is 3 seconds. ### WriteTimeout Sets the timeout value of `time.Duration` for Write call of `logger.Post`. Since the default is zero value, Write will not time out. ### BufferLimit Sets the number of events buffered on the memory. Records will be stored in memory up to this number. If the buffer is full, the call to record logs will fail. The default is 8192. ### RetryWait Set the duration of the initial wait for the first retry, in milliseconds. The actual retry wait will be `r * 1.5^(N-1)` (r: this value, N: the number of retries). The default is 500. ### MaxRetry Sets the maximum number of retries. If the number of retries become larger than this value, the write/send operation will fail. The default is 13. ### MaxRetryWait The maximum duration of wait between retries, in milliseconds. If the calculated retry wait is larger than this value, the actual retry wait will be this value. The default is 60,000 (60 seconds). ### TagPrefix Sets the prefix string of the tag. Prefix will be appended with a dot `.`, like `ppp.tag` (ppp: the value of this parameter, tag: the tag string specified in a call). The default is blank. ### Async Enable asynchronous I/O (connect and write) for sending events to Fluentd. The default is false. ### ForceStopAsyncSend When Async is enabled, immediately discard the event queue on close() and return (instead of trying MaxRetry times for each event in the queue before returning) The default is false. ### AsyncResultCallback When Async is enabled, if this is callback is provided, it will be called on every write to Fluentd. The callback function takes two arguments - a `[]byte` of the message that was to be sent and an `error`. If the `error` is not nil this means the delivery of the message was unsuccessful. ### AsyncReconnectInterval When async is enabled, this option defines the interval (ms) at which the connection to the fluentd-address is re-established. This option is useful if the address may resolve to one or more IP addresses, e.g. a Consul service address. ### SubSecondPrecision Enable time encoding as EventTime, which contains sub-second precision values. The messages encoded with this option can be received only by Fluentd v0.14 or later. The default is false. ### MarshalAsJson Enable Json data marshaling to send messages using Json format (instead of the standard MessagePack). It is supported by Fluentd `in_forward` plugin. The default is false. ### RequestAck Sets whether to request acknowledgment from Fluentd to increase the reliability of the connection. The default is false. ### TlsInsecureSkipVerify Skip verifying the server certificate. Useful for development and testing. The default is false. ## FAQ ### Does this logger support the features of Fluentd Forward Protocol v1? "the features" includes heartbeat messages (for TCP keepalive), TLS transport and shared key authentication. This logger doesn't support those features. Patches are welcome! ### Is it allowed to call `Fluent.Post()` after connection close? Before v1.8.0, the Fluent logger silently reopened connections whenever `Fluent.Post()` was called. ```go logger, _ := fluent.New(fluent.Config{}) logger.Post(tag, data) logger.Close() logger.Post(tag, data) /* reopen connection */ ``` However, this behavior was confusing, in particular when multiple goroutines were involved. Starting v1.8.0, the logger no longer accepts `Fluent.Post()` after `Fluent.Close()`, and instead returns a "Logger already closed" error. ## Tests ``` go test ``` fluent-logger-golang-1.9.0/_examples/000077500000000000000000000000001416061525300175205ustar00rootroot00000000000000fluent-logger-golang-1.9.0/_examples/main.go000066400000000000000000000010211416061525300207650ustar00rootroot00000000000000package main import ( "fmt" "log" "time" "../fluent" ) func main() { logger, err := fluent.New(fluent.Config{FluentPort: 24224, FluentHost: "127.0.0.1"}) if err != nil { fmt.Println(err) } defer logger.Close() tag := "myapp.access" var data = map[string]string{ "foo": "bar", "hoge": "hoge"} for i := 0; i < 100; i++ { e := logger.Post(tag, data) if e != nil { log.Println("Error while posting log: ", e) } else { log.Println("Success to post log") } time.Sleep(1000 * time.Millisecond) } } fluent-logger-golang-1.9.0/fluent/000077500000000000000000000000001416061525300170405ustar00rootroot00000000000000fluent-logger-golang-1.9.0/fluent/fluent.go000066400000000000000000000422521416061525300206710ustar00rootroot00000000000000package fluent import ( "context" "crypto/tls" "encoding/json" "errors" "fmt" "math" "math/rand" "net" "os" "reflect" "strconv" "sync" "time" "bytes" "encoding/base64" "encoding/binary" "github.com/tinylib/msgp/msgp" ) const ( defaultHost = "127.0.0.1" defaultNetwork = "tcp" defaultSocketPath = "" defaultPort = 24224 defaultTimeout = 3 * time.Second defaultWriteTimeout = time.Duration(0) // Write() will not time out defaultBufferLimit = 8 * 1024 defaultRetryWait = 500 defaultMaxRetryWait = 60000 defaultMaxRetry = 13 defaultReconnectWaitIncreRate = 1.5 // Default sub-second precision value to false since it is only compatible // with fluentd versions v0.14 and above. defaultSubSecondPrecision = false // Default value whether to skip checking insecure certs on TLS connections. defaultTlsInsecureSkipVerify = false ) // randomGenerator is used by getUniqueId to generate ack hashes. Its value is replaced // during tests with a deterministic function. var randomGenerator = rand.Uint64 type Config struct { FluentPort int `json:"fluent_port"` FluentHost string `json:"fluent_host"` FluentNetwork string `json:"fluent_network"` FluentSocketPath string `json:"fluent_socket_path"` Timeout time.Duration `json:"timeout"` WriteTimeout time.Duration `json:"write_timeout"` BufferLimit int `json:"buffer_limit"` RetryWait int `json:"retry_wait"` MaxRetry int `json:"max_retry"` MaxRetryWait int `json:"max_retry_wait"` TagPrefix string `json:"tag_prefix"` Async bool `json:"async"` ForceStopAsyncSend bool `json:"force_stop_async_send"` AsyncResultCallback func(data []byte, err error) // Deprecated: Use Async instead AsyncConnect bool `json:"async_connect"` MarshalAsJSON bool `json:"marshal_as_json"` // AsyncReconnectInterval defines the interval (ms) at which the connection // to the fluentd-address is re-established. This option is useful if the address // may resolve to one or more IP addresses, e.g. a Consul service address. AsyncReconnectInterval int `json:"async_reconnect_interval"` // Sub-second precision timestamps are only possible for those using fluentd // v0.14+ and serializing their messages with msgpack. SubSecondPrecision bool `json:"sub_second_precision"` // RequestAck sends the chunk option with a unique ID. The server will // respond with an acknowledgement. This option improves the reliability // of the message transmission. RequestAck bool `json:"request_ack"` // Flag to skip verifying insecure certs on TLS connections TlsInsecureSkipVerify bool `json: "tls_insecure_skip_verify"` } type ErrUnknownNetwork struct { network string } func (e *ErrUnknownNetwork) Error() string { return "unknown network " + e.network } func NewErrUnknownNetwork(network string) error { return &ErrUnknownNetwork{network} } type msgToSend struct { data []byte ack string } type Fluent struct { Config dialer dialer // stopRunning is used in async mode to signal to run() it should abort. stopRunning chan struct{} // cancelDialings is used by Close() to stop any in-progress dialing. cancelDialings context.CancelFunc pending chan *msgToSend pendingMutex sync.RWMutex closed bool wg sync.WaitGroup // time at which the most recent connection to fluentd-address was established. latestReconnectTime time.Time muconn sync.RWMutex conn net.Conn } type dialer interface { DialContext(ctx context.Context, network, address string) (net.Conn, error) } // New creates a new Logger. func New(config Config) (*Fluent, error) { if config.Timeout == 0 { config.Timeout = defaultTimeout } return newWithDialer(config, &net.Dialer{ Timeout: config.Timeout, }) } func newWithDialer(config Config, d dialer) (f *Fluent, err error) { if config.FluentNetwork == "" { config.FluentNetwork = defaultNetwork } if config.FluentHost == "" { config.FluentHost = defaultHost } if config.FluentPort == 0 { config.FluentPort = defaultPort } if config.FluentSocketPath == "" { config.FluentSocketPath = defaultSocketPath } if config.WriteTimeout == 0 { config.WriteTimeout = defaultWriteTimeout } if config.BufferLimit == 0 { config.BufferLimit = defaultBufferLimit } if config.RetryWait == 0 { config.RetryWait = defaultRetryWait } if config.MaxRetry == 0 { config.MaxRetry = defaultMaxRetry } if config.MaxRetryWait == 0 { config.MaxRetryWait = defaultMaxRetryWait } if !config.TlsInsecureSkipVerify { config.TlsInsecureSkipVerify = defaultTlsInsecureSkipVerify } if config.AsyncConnect { fmt.Fprintf(os.Stderr, "fluent#New: AsyncConnect is now deprecated, please use Async instead") config.Async = config.Async || config.AsyncConnect } if config.Async { ctx, cancel := context.WithCancel(context.Background()) f = &Fluent{ Config: config, dialer: d, stopRunning: make(chan struct{}), cancelDialings: cancel, pending: make(chan *msgToSend, config.BufferLimit), pendingMutex: sync.RWMutex{}, muconn: sync.RWMutex{}, } f.wg.Add(1) go f.run(ctx) } else { f = &Fluent{ Config: config, dialer: d, muconn: sync.RWMutex{}, } err = f.connect(context.Background()) } return } // Post writes the output for a logging event. // // Examples: // // // send map[string] // mapStringData := map[string]string{ // "foo": "bar", // } // f.Post("tag_name", mapStringData) // // // send message with specified time // mapStringData := map[string]string{ // "foo": "bar", // } // tm := time.Now() // f.PostWithTime("tag_name", tm, mapStringData) // // // send struct // structData := struct { // Name string `msg:"name"` // } { // "john smith", // } // f.Post("tag_name", structData) // func (f *Fluent) Post(tag string, message interface{}) error { timeNow := time.Now() return f.PostWithTime(tag, timeNow, message) } func (f *Fluent) PostWithTime(tag string, tm time.Time, message interface{}) error { if len(f.TagPrefix) > 0 { tag = f.TagPrefix + "." + tag } if m, ok := message.(msgp.Marshaler); ok { return f.EncodeAndPostData(tag, tm, m) } msg := reflect.ValueOf(message) msgtype := msg.Type() if msgtype.Kind() == reflect.Struct { // message should be tagged by "codec" or "msg" kv := make(map[string]interface{}) fields := msgtype.NumField() for i := 0; i < fields; i++ { field := msgtype.Field(i) value := msg.FieldByIndex(field.Index) // ignore unexported fields if !value.CanInterface() { continue } name := field.Name if n1 := field.Tag.Get("msg"); n1 != "" { name = n1 } else if n2 := field.Tag.Get("codec"); n2 != "" { name = n2 } kv[name] = value.Interface() } return f.EncodeAndPostData(tag, tm, kv) } if msgtype.Kind() != reflect.Map { return errors.New("fluent#PostWithTime: message must be a map") } else if msgtype.Key().Kind() != reflect.String { return errors.New("fluent#PostWithTime: map keys must be strings") } kv := make(map[string]interface{}) for _, k := range msg.MapKeys() { kv[k.String()] = msg.MapIndex(k).Interface() } return f.EncodeAndPostData(tag, tm, kv) } func (f *Fluent) EncodeAndPostData(tag string, tm time.Time, message interface{}) error { var msg *msgToSend var err error if msg, err = f.EncodeData(tag, tm, message); err != nil { return fmt.Errorf("fluent#EncodeAndPostData: can't convert '%#v' to msgpack:%v", message, err) } return f.postRawData(msg) } // Deprecated: Use EncodeAndPostData instead func (f *Fluent) PostRawData(msg *msgToSend) { f.postRawData(msg) } func (f *Fluent) postRawData(msg *msgToSend) error { if f.Config.Async { return f.appendBuffer(msg) } // Synchronous write if f.closed { return fmt.Errorf("fluent#postRawData: Logger already closed") } return f.writeWithRetry(context.Background(), msg) } // For sending forward protocol adopted JSON type MessageChunk struct { message Message } // Golang default marshaler does not support // ["value", "value2", {"key":"value"}] style marshaling. // So, it should write JSON marshaler by hand. func (chunk *MessageChunk) MarshalJSON() ([]byte, error) { data, err := json.Marshal(chunk.message.Record) if err != nil { return nil, err } option, err := json.Marshal(chunk.message.Option) if err != nil { return nil, err } return []byte(fmt.Sprintf("[\"%s\",%d,%s,%s]", chunk.message.Tag, chunk.message.Time, data, option)), err } // getUniqueID returns a base64 encoded unique ID that can be used for chunk/ack // mechanism, see // https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1#option func getUniqueID(timeUnix int64) (string, error) { buf := bytes.NewBuffer(nil) enc := base64.NewEncoder(base64.StdEncoding, buf) if err := binary.Write(enc, binary.LittleEndian, timeUnix); err != nil { enc.Close() return "", err } if err := binary.Write(enc, binary.LittleEndian, randomGenerator()); err != nil { enc.Close() return "", err } // encoder needs to be closed before buf.String(), defer does not work // here enc.Close() return buf.String(), nil } func (f *Fluent) EncodeData(tag string, tm time.Time, message interface{}) (msg *msgToSend, err error) { option := make(map[string]string) msg = &msgToSend{} timeUnix := tm.Unix() if f.Config.RequestAck { var err error msg.ack, err = getUniqueID(timeUnix) if err != nil { return nil, err } option["chunk"] = msg.ack } if f.Config.MarshalAsJSON { m := Message{Tag: tag, Time: timeUnix, Record: message, Option: option} chunk := &MessageChunk{message: m} msg.data, err = json.Marshal(chunk) } else if f.Config.SubSecondPrecision { m := &MessageExt{Tag: tag, Time: EventTime(tm), Record: message, Option: option} msg.data, err = m.MarshalMsg(nil) } else { m := &Message{Tag: tag, Time: timeUnix, Record: message, Option: option} msg.data, err = m.MarshalMsg(nil) } return } // Close closes the connection, waiting for pending logs to be sent. If the client is // running in async mode, the run() goroutine exits before Close() returns. func (f *Fluent) Close() (err error) { if f.Config.Async { f.pendingMutex.Lock() if f.closed { f.pendingMutex.Unlock() return nil } f.closed = true f.pendingMutex.Unlock() if f.Config.ForceStopAsyncSend { close(f.stopRunning) f.cancelDialings() } close(f.pending) // If ForceStopAsyncSend is false, all logs in the channel have to be sent // before closing the connection. At this point closed is true so no more // logs are written to the channel and f.pending has been closed, so run() // goroutine will exit as soon as all logs in the channel are sent. if !f.Config.ForceStopAsyncSend { f.wg.Wait() } } f.muconn.Lock() f.close() f.closed = true f.muconn.Unlock() // If ForceStopAsyncSend is true, we shall close the connection before waiting for // run() goroutine to exit to be sure we aren't waiting on ack message that might // never come (eg. because fluentd server is down). However we want to be sure the // run() goroutine stops before returning from Close(). if f.Config.ForceStopAsyncSend { f.wg.Wait() } return } // appendBuffer appends data to buffer with lock. func (f *Fluent) appendBuffer(msg *msgToSend) error { f.pendingMutex.RLock() defer f.pendingMutex.RUnlock() if f.closed { return fmt.Errorf("fluent#appendBuffer: Logger already closed") } select { case f.pending <- msg: default: return fmt.Errorf("fluent#appendBuffer: Buffer full, limit %v", f.Config.BufferLimit) } return nil } // close closes the connection. Callers should take care of locking muconn first. func (f *Fluent) close() { if f.conn != nil { f.conn.Close() f.conn = nil } } // connect establishes a new connection using the specified transport. Caller should // take care of locking muconn first. func (f *Fluent) connect(ctx context.Context) (err error) { switch f.Config.FluentNetwork { case "tcp": f.conn, err = f.dialer.DialContext(ctx, f.Config.FluentNetwork, f.Config.FluentHost+":"+strconv.Itoa(f.Config.FluentPort)) case "tls": tlsConfig := &tls.Config{InsecureSkipVerify: f.Config.TlsInsecureSkipVerify} f.conn, err = tls.DialWithDialer( &net.Dialer{Timeout: f.Config.Timeout}, "tcp", f.Config.FluentHost+":"+strconv.Itoa(f.Config.FluentPort), tlsConfig, ) case "unix": f.conn, err = f.dialer.DialContext(ctx, f.Config.FluentNetwork, f.Config.FluentSocketPath) default: err = NewErrUnknownNetwork(f.Config.FluentNetwork) } if err == nil { f.latestReconnectTime = time.Now() } return err } var errIsClosing = errors.New("fluent logger is closing") // Caller should take care of locking muconn first. func (f *Fluent) connectWithRetry(ctx context.Context) error { // A Time channel is used instead of time.Sleep() to avoid blocking this // goroutine during way too much time (because of the exponential back-off // retry). // time.NewTimer() is used instead of time.After() to avoid leaking the // timer channel (cf. https://pkg.go.dev/time#After). timeout := time.NewTimer(time.Duration(0)) defer func() { // timeout.Stop() is called in a function literal instead of being // defered directly as it's re-assigned below when the retry loop spins. timeout.Stop() }() for i := 0; i < f.Config.MaxRetry; i++ { select { case <-timeout.C: err := f.connect(ctx) if err == nil { return nil } if _, ok := err.(*ErrUnknownNetwork); ok { return err } if err == context.Canceled { return errIsClosing } waitTime := f.Config.RetryWait * e(defaultReconnectWaitIncreRate, float64(i-1)) if waitTime > f.Config.MaxRetryWait { waitTime = f.Config.MaxRetryWait } timeout = time.NewTimer(time.Duration(waitTime) * time.Millisecond) case <-ctx.Done(): return errIsClosing } } return fmt.Errorf("could not connect to fluentd after %d retries", f.Config.MaxRetry) } // run is the goroutine used to unqueue and write logs in async mode. That // goroutine is meant to run during the whole life of the Fluent logger. func (f *Fluent) run(ctx context.Context) { for { select { case entry, ok := <-f.pending: // f.stopRunning is closed before f.pending only when ForceStopAsyncSend // is enabled. Otherwise, f.pending is closed when Close() is called. if !ok { f.wg.Done() return } if f.AsyncReconnectInterval > 0 { if time.Since(f.latestReconnectTime) > time.Duration(f.AsyncReconnectInterval)*time.Millisecond { f.muconn.Lock() f.close() f.connectWithRetry(ctx) f.muconn.Unlock() } } err := f.writeWithRetry(ctx, entry) if err != nil && err != errIsClosing { fmt.Fprintf(os.Stderr, "[%s] Unable to send logs to fluentd, reconnecting...\n", time.Now().Format(time.RFC3339)) } if f.AsyncResultCallback != nil { var data []byte if entry != nil { data = entry.data } f.AsyncResultCallback(data, err) } case <-f.stopRunning: fmt.Fprintf(os.Stderr, "[%s] Discarding queued events...\n", time.Now().Format(time.RFC3339)) f.wg.Done() return } } } func e(x, y float64) int { return int(math.Pow(x, y)) } func (f *Fluent) writeWithRetry(ctx context.Context, msg *msgToSend) error { for i := 0; i < f.Config.MaxRetry; i++ { if retry, err := f.write(ctx, msg); !retry { return err } } return fmt.Errorf("fluent#write: failed to write after %d attempts", f.Config.MaxRetry) } // write writes the provided msg to fluentd server. Its first return values is // a bool indicating whether the write should be retried. // This method relies on function literals to execute muconn.Unlock or // muconn.RUnlock in deferred calls to ensure the mutex is unlocked even in // the case of panic recovering. func (f *Fluent) write(ctx context.Context, msg *msgToSend) (bool, error) { closer := func() { f.muconn.Lock() defer f.muconn.Unlock() f.close() } if err := func() (err error) { f.muconn.Lock() defer f.muconn.Unlock() if f.conn == nil { err = f.connectWithRetry(ctx) } return err }(); err != nil { // Here, we don't want to retry the write since connectWithRetry already // retries Config.MaxRetry times to connect. return false, fmt.Errorf("fluent#write: %v", err) } if err := func() (err error) { f.muconn.RLock() defer f.muconn.RUnlock() if f.conn == nil { return fmt.Errorf("connection has been closed before writing to it") } t := f.Config.WriteTimeout if time.Duration(0) < t { f.conn.SetWriteDeadline(time.Now().Add(t)) } else { f.conn.SetWriteDeadline(time.Time{}) } _, err = f.conn.Write(msg.data) return err }(); err != nil { closer() return true, fmt.Errorf("fluent#write: %v", err) } // Acknowledgment check if msg.ack != "" { resp := &AckResp{} var err error if f.Config.MarshalAsJSON { dec := json.NewDecoder(f.conn) err = dec.Decode(resp) } else { r := msgp.NewReader(f.conn) err = resp.DecodeMsg(r) } if err != nil || resp.Ack != msg.ack { fmt.Fprintf(os.Stderr, "fluent#write: message ack (%s) doesn't match expected one (%s). Closing connection...", resp.Ack, msg.ack) closer() return true, err } } return false, nil } fluent-logger-golang-1.9.0/fluent/fluent_test.go000066400000000000000000000631141416061525300217300ustar00rootroot00000000000000package fluent import ( "bytes" "context" "encoding/json" "errors" "fmt" "io/ioutil" "net" "reflect" "runtime" "testing" "time" "github.com/bmizerany/assert" "github.com/tinylib/msgp/msgp" ) func init() { // randomGenerator points to rand.Uint64 by default. Unfortunately, even when it's // seeded, it produces different values from time to time and thus is not fully // deterministic. This prevents writing stable tests for RequestAck config option. // Thus we need to change it to ensure the hashes are stable during tests. randomGenerator = func() uint64 { return 1 } } func newTestDialer() *testDialer { return &testDialer{ dialCh: make(chan *Conn), } } // testDialer is a stub for net.Dialer. It implements the Dial() method used by // the logger to connect to Fluentd. It uses a *Conn channel to let the tests // synchronize with calls to Dial() and let them define what each call to Dial() // should return. This is especially useful for testing edge cases like // transient connection failures. // To help write test cases with succeeding or failing connection dialing, testDialer // provides waitForNextDialing(). Any call to Dial() from the logger should be matched // with a call to waitForNextDialing() in the test cases. // // For instance, to test an async logger that have to dial 4 times before succeeding, // the test should look like this: // // d := newTestDialer() // Create a new stubbed dialer // cfg := Config{ // Async: true, // // ... // } // f := newWithDialer(cfg, d) // Create a fluent logger using the stubbed dialer // f.EncodeAndPostData("tag_name", time.Unix(1482493046, 0), map[string]string{"foo": "bar"}) // // d.waitForNextDialing(false, false) // 1st dialing attempt fails // d.waitForNextDialing(false, false) // 2nd attempt fails too // d.waitForNextDialing(false, false) // 3rd attempt fails too // d.waitForNextDialing(true, false) // Finally the 4th attempt succeeds // // Note that in the above example, the logger operates in async mode. As such, // a call to Post, PostWithTime or EncodeAndPostData is needed *before* calling // waitForNextDialing(), as in async mode the logger initializes its connection // lazily, in a separate goroutine. // This also means non-async loggers can't be tested exactly the same way, as the // dialing isn't done lazily but during the logger initialization. To test such // case, you have to put the calls to newWithDialer() and to EncodeAndPostData() // into their own goroutine. An example: // // d := newTestDialer() // Create a new stubbed dialer // cfg := Config{ // Async: false, // // ... // } // go func() { // f := newWithDialer(cfg, d) // Create a fluent logger using the stubbed dialer // f.Close() // }() // // d.waitForNextDialing(false, false) // 1st dialing attempt fails // d.waitForNextDialing(false, false) // 2nd attempt fails too // d.waitForNextDialing(false, false) // 3rd attempt fails too // d.waitForNextDialing(true, false) // Finally the 4th attempt succeeds // // Moreover, waitForNextDialing() returns a *Conn which extends net.Conn to provide testing // facilities. For instance, you can call waitForNextWrite() on these connections, to // specify how the next Conn.Write() call behaves (e.g. accept or reject it, or make a // specific ack checksum available) and to assert what is sent to Fluentd (when the write // is accepted). Again, any call to Write() on the logger side have to be matched with // a call to waitForNextWrite() in the test cases. // // Here's a full example: // // d := newTestDialer() // cfg := Config{Async: true} // // f := newWithDialer(cfg, d) // f.EncodeAndPostData("tag_name", time.Unix(1482493046, 0), map[string]string{"foo": "bar"}) // // conn := d.waitForNextDialing(true, false) // Accept the dialing // conn.waitForNextWrite(false, "") // Discard the 1st attempt to write the message // // conn := d.waitForNextDialing(true, false) // assertReceived(t, // t is *testing.T // conn.waitForNextWrite(true, ""), // "[\"tag_name\",1482493046,{\"foo\":\"bar\"},{}]") // // f.EncodeAndPostData("something_else", time.Unix(1482493050, 0), map[string]string{"bar": "baz"}) // assertReceived(t, // t is *testing.T // conn.waitForNextWrite(true, ""), // "[\"something_else\",1482493050,{\"bar\":\"baz\"},{}]") // // In this example, the 1st connection dialing succeeds but the 1st attempt to write the // message is discarded. As the logger discards the connection whenever a message // couldn't be written, it tries to re-dial and thus we need to accept the dialing again. // Then the write is retried and accepted. When a second message is written, the write is // accepted straightaway. Moreover, the messages written to the connections are asserted // using assertReceived() to make sure the logger encodes the messages properly. // // Again, the example above is using async mode thus, calls to f and conn are running in // the same goroutine. However in sync mode, all calls to f.EncodeAndPostData() as well // as the logger initialization shall be placed in a separate goroutine or the code // allowing the dialing and writing attempts (eg. waitForNextDialing() & waitForNextWrite()) // would never be reached. type testDialer struct { dialCh chan *Conn } // DialContext is the stubbed method called by the logger to establish the connection to // Fluentd. It is paired with waitForNextDialing(). func (d *testDialer) DialContext(ctx context.Context, _, _ string) (net.Conn, error) { // It waits for a *Conn to be pushed into dialCh using waitForNextDialing(). When the // *Conn is nil, the Dial is deemed to fail. select { case conn := <-d.dialCh: if conn == nil { return nil, errors.New("failed to dial") } return conn, nil case <-ctx.Done(): return nil, errors.New("failed to dial") } } // waitForNextDialing is the method used by test cases below to indicate whether the next // dialing attempt made by the logger should succeed or not. See examples provided on // testDialer docs. func (d *testDialer) waitForNextDialing(accept bool, delayReads bool) *Conn { var conn *Conn if accept { conn = &Conn{ nextWriteAttemptCh: make(chan nextWrite), writtenCh: make(chan []byte), } if delayReads { conn.delayNextReadCh = make(chan struct{}) } } d.dialCh <- conn return conn } // assertReceived is used below by test cases to assert the content written to a *Conn // matches an expected string. This is generally used in conjunction with // Conn.waitForNextWrite(). func assertReceived(t *testing.T, rcv []byte, expected string) { if string(rcv) != expected { t.Fatalf("got %s, expect %s", string(rcv), expected) } } // Conn extends net.Conn to add channels used to synchronise across goroutines, eg. // between the goroutine doing the dialing (through newWithDialer in sync mode, or the // first message logging in async mode) and the testing goroutine (making calls to // Conn.waitForNextWrite()). // This should be of low importance if you're not trying to understand/change how // waitFor...() methods work. See examples provided in testDialer docs for higher // level details. type Conn struct { net.Conn buf []byte writeDeadline time.Time // nextWriteAttemptCh is used by waitForNextWrite() to let Write() know if the next write // attempt should succeed or fail. nextWriteAttemptCh chan nextWrite // writtenCh is used by Write() to signal to waitForNextWrite() when a write // happened. writtenCh chan []byte // delayNextReadCh is used to delay next conn.Read() attempt when testing ack resp. delayNextReadCh chan struct{} } // nextWrite is the struct passed by Conn.waitForNextWrite() to Conn.Write() through // Conn.nextWriteAttemptCh to let Write() know if it should accept or discard the next write // operation and what ack checksum should be made readable from the connection. // This should be of low importance if you're not trying to understand/change how // waitFor...() methods work. See examples provided in testDialer docs for higher // level details. type nextWrite struct { accept bool ack string } // waitForNextWrite is the method used to tell how the next write made by the logger // should behave. It can either accept or discard the next write operation. Moreover // an ack checksum can be passed such that the next Write operation will make it // readable from the connection, as the logger will try to read it to ack the Write // operation. See examples provided in testDialer docs. func (c *Conn) waitForNextWrite(accept bool, ack string) []byte { c.nextWriteAttemptCh <- nextWrite{accept, ack} if accept { return <-c.writtenCh } return []byte{} } // Read is a stubbed version of net.Conn Read() that returns the ack checksum of the last // Write operation. func (c *Conn) Read(b []byte) (int, error) { if c.delayNextReadCh != nil { select { case _, ok := <-c.delayNextReadCh: if !ok { return 0, errors.New("connection has been closed") } default: } } copy(b, c.buf) return len(c.buf), nil } // Write is a stubbed version of net.Conn Write(). Its behavior is determined by the last // call to waitForNextWrite(). See examples provided in testDialer docs. func (c *Conn) Write(b []byte) (int, error) { next, ok := nextWrite{true, ""}, true if c.nextWriteAttemptCh != nil { next, ok = <-c.nextWriteAttemptCh } if !next.accept || !ok { return 0, errors.New("transient write failure") } // Write the acknowledgment to c.buf to make it available to subsequent // call to Read(). c.buf = make([]byte, len(next.ack)) copy(c.buf, next.ack) // Write the payload received to writtenCh to assert on it. if c.writtenCh != nil { c.writtenCh <- b } return len(b), nil } func (c *Conn) SetWriteDeadline(t time.Time) error { c.writeDeadline = t return nil } func (c *Conn) Close() error { if c.delayNextReadCh != nil { close(c.delayNextReadCh) } return nil } func Test_New_itShouldUseDefaultConfigValuesIfNoOtherProvided(t *testing.T) { f, _ := New(Config{}) assert.Equal(t, f.Config.FluentPort, defaultPort) assert.Equal(t, f.Config.FluentHost, defaultHost) assert.Equal(t, f.Config.Timeout, defaultTimeout) assert.Equal(t, f.Config.WriteTimeout, defaultWriteTimeout) assert.Equal(t, f.Config.BufferLimit, defaultBufferLimit) assert.Equal(t, f.Config.FluentNetwork, defaultNetwork) assert.Equal(t, f.Config.FluentSocketPath, defaultSocketPath) } func Test_New_itShouldUseUnixDomainSocketIfUnixSocketSpecified(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("windows not supported") } socketFile := "/tmp/fluent-logger-golang.sock" network := "unix" l, err := net.Listen(network, socketFile) if err != nil { t.Error(err) return } defer l.Close() f, err := New(Config{ FluentNetwork: network, FluentSocketPath: socketFile}) if err != nil { t.Error(err) return } defer f.Close() assert.Equal(t, f.Config.FluentNetwork, network) assert.Equal(t, f.Config.FluentSocketPath, socketFile) socketFile = "/tmp/fluent-logger-golang-xxx.sock" network = "unixxxx" fUnknown, err := New(Config{ FluentNetwork: network, FluentSocketPath: socketFile}) if _, ok := err.(*ErrUnknownNetwork); !ok { t.Errorf("err type: %T", err) } if err == nil { t.Error(err) fUnknown.Close() return } } func Test_New_itShouldUseConfigValuesFromArguments(t *testing.T) { f, _ := New(Config{FluentPort: 6666, FluentHost: "foobarhost"}) assert.Equal(t, f.Config.FluentPort, 6666) assert.Equal(t, f.Config.FluentHost, "foobarhost") } func Test_New_itShouldUseConfigValuesFromMashalAsJSONArgument(t *testing.T) { f, _ := New(Config{MarshalAsJSON: true}) assert.Equal(t, f.Config.MarshalAsJSON, true) } func Test_MarshalAsMsgpack(t *testing.T) { f := &Fluent{Config: Config{}} tag := "tag" var data = map[string]string{ "foo": "bar", "hoge": "hoge"} tm := time.Unix(1267867237, 0) result, err := f.EncodeData(tag, tm, data) if err != nil { t.Error(err) } actual := string(result.data) // map entries are disordered in golang expected1 := "\x94\xA3tag\xD2K\x92\u001Ee\x82\xA3foo\xA3bar\xA4hoge\xA4hoge\x80" expected2 := "\x94\xA3tag\xD2K\x92\u001Ee\x82\xA4hoge\xA4hoge\xA3foo\xA3bar\x80" if actual != expected1 && actual != expected2 { t.Errorf("got %+v,\n except %+v\n or %+v", actual, expected1, expected2) } } func Test_SubSecondPrecision(t *testing.T) { // Setup the test subject fluent := &Fluent{ Config: Config{ SubSecondPrecision: true, }, } fluent.conn = &Conn{} // Exercise the test subject timestamp := time.Unix(1267867237, 256) encodedData, err := fluent.EncodeData("tag", timestamp, map[string]string{ "foo": "bar", }) // Assert no encoding errors and that the timestamp has been encoded into // the message as expected. if err != nil { t.Error(err) } // 8 bytes timestamp can be represented using ext 8 or fixext 8 expected1 := "\x94\xA3tag\xC7\x08\x00K\x92\u001Ee\x00\x00\x01\x00\x81\xA3foo\xA3bar\x80" expected2 := "\x94\xa3tag\xD7\x00K\x92\x1Ee\x00\x00\x01\x00\x81\xA3foo\xA3bar\x80" actual := string(encodedData.data) if actual != expected1 && actual != expected2 { t.Errorf("got %+v,\n except %+v\n or %+v", actual, expected1, expected2) } } func Test_MarshalAsJSON(t *testing.T) { f := &Fluent{Config: Config{MarshalAsJSON: true}} var data = map[string]string{ "foo": "bar", "hoge": "hoge"} tm := time.Unix(1267867237, 0) result, err := f.EncodeData("tag", tm, data) if err != nil { t.Error(err) } // json.Encode marshals map keys in the order, so this expectation is safe expected := `["tag",1267867237,{"foo":"bar","hoge":"hoge"},{}]` actual := string(result.data) if actual != expected { t.Errorf("got %s, except %s", actual, expected) } } func TestJsonConfig(t *testing.T) { b, err := ioutil.ReadFile(`testdata/config.json`) if err != nil { t.Error(err) } var got Config expect := Config{ FluentPort: 8888, FluentHost: "localhost", FluentNetwork: "tcp", FluentSocketPath: "/var/tmp/fluent.sock", Timeout: 3000, WriteTimeout: 6000, BufferLimit: 10, RetryWait: 5, MaxRetry: 3, TagPrefix: "fluent", Async: false, ForceStopAsyncSend: false, MarshalAsJSON: true, } err = json.Unmarshal(b, &got) if err != nil { t.Error(err) } if !reflect.DeepEqual(expect, got) { t.Errorf("got %v, except %v", got, expect) } } func TestPostWithTime(t *testing.T) { testcases := map[string]Config{ "with Async": { Async: true, MarshalAsJSON: true, TagPrefix: "acme", }, "without Async": { Async: false, MarshalAsJSON: true, TagPrefix: "acme", }, } for tcname := range testcases { t.Run(tcname, func(t *testing.T) { tc := testcases[tcname] t.Parallel() d := newTestDialer() var f *Fluent defer func() { if f != nil { f.Close() } }() go func() { var err error if f, err = newWithDialer(tc, d); err != nil { t.Errorf("Unexpected error: %v", err) } _ = f.PostWithTime("tag_name", time.Unix(1482493046, 0), map[string]string{"foo": "bar"}) _ = f.PostWithTime("tag_name", time.Unix(1482493050, 0), map[string]string{"fluentd": "is awesome"}) _ = f.PostWithTime("tag_name", time.Unix(1634263200, 0), struct {Welcome string `msg:"welcome"`; cannot string}{"to use", "see me"}) }() conn := d.waitForNextDialing(true, false) assertReceived(t, conn.waitForNextWrite(true, ""), "[\"acme.tag_name\",1482493046,{\"foo\":\"bar\"},{}]") assertReceived(t, conn.waitForNextWrite(true, ""), "[\"acme.tag_name\",1482493050,{\"fluentd\":\"is awesome\"},{}]") assertReceived(t, conn.waitForNextWrite(true, ""), "[\"acme.tag_name\",1634263200,{\"welcome\":\"to use\"},{}]") }) } } func TestReconnectAndResendAfterTransientFailure(t *testing.T) { testcases := map[string]Config{ "with Async": { Async: true, MarshalAsJSON: true, }, "without Async": { Async: false, MarshalAsJSON: true, }, } for tcname := range testcases { t.Run(tcname, func(t *testing.T) { tc := testcases[tcname] t.Parallel() d := newTestDialer() var f *Fluent defer func() { if f != nil { f.Close() } }() go func() { var err error if f, err = newWithDialer(tc, d); err != nil { t.Errorf("Unexpected error: %v", err) } _ = f.EncodeAndPostData("tag_name", time.Unix(1482493046, 0), map[string]string{"foo": "bar"}) _ = f.EncodeAndPostData("tag_name", time.Unix(1482493050, 0), map[string]string{"fluentd": "is awesome"}) }() // Accept the first connection dialing and write. conn := d.waitForNextDialing(true, false) assertReceived(t, conn.waitForNextWrite(true, ""), "[\"tag_name\",1482493046,{\"foo\":\"bar\"},{}]") // The next write will fail and the next connection dialing will be dropped // to test if the logger is reconnecting as expected. conn.waitForNextWrite(false, "") d.waitForNextDialing(false, false) // Next, we allow a new connection to be established and we allow the last message to be written. conn = d.waitForNextDialing(true, false) assertReceived(t, conn.waitForNextWrite(true, ""), "[\"tag_name\",1482493050,{\"fluentd\":\"is awesome\"},{}]") }) } } func timeout(t *testing.T, duration time.Duration, fn func(), reason string) { done := make(chan struct{}) go func() { fn() done <- struct{}{} }() select { case <-time.After(duration): t.Fatalf("time out after %s: %s", duration.String(), reason) case <-done: return } } func TestCloseOnFailingAsyncConnect(t *testing.T) { testcases := map[string]Config{ "with ForceStopAsyncSend and with RequestAck": { Async: true, ForceStopAsyncSend: true, RequestAck: true, }, "with ForceStopAsyncSend and without RequestAck": { Async: true, ForceStopAsyncSend: true, RequestAck: false, }, "without ForceStopAsyncSend and with RequestAck": { Async: true, ForceStopAsyncSend: false, RequestAck: true, }, "without ForceStopAsyncSend and without RequestAck": { Async: true, ForceStopAsyncSend: false, RequestAck: false, }, } for tcname := range testcases { t.Run(tcname, func(t *testing.T) { tc := testcases[tcname] t.Parallel() d := newTestDialer() f, err := newWithDialer(tc, d) if err != nil { t.Errorf("Unexpected error: %v", err) } timeout(t, 1*time.Second, func() { f.Close() }, "failed to close the logger") }) } } func ackRespMsgp(t *testing.T, ack string) string { msg := AckResp{ack} buf := &bytes.Buffer{} ackW := msgp.NewWriter(buf) if err := msg.EncodeMsg(ackW); err != nil { t.Fatalf("Unexpected error: %v", err) } ackW.Flush() return buf.String() } func TestNoPanicOnAsyncClose(t *testing.T) { testcases := []struct { name string config Config shouldError bool }{ { name: "Channel closed before write", config: Config{ Async: true, }, shouldError: true, }, { name: "Channel not closed at all", config: Config{ Async: true, }, shouldError: false, }, } for _, testcase := range testcases { t.Run(testcase.name, func(t *testing.T) { t.Parallel() d := newTestDialer() f, err := newWithDialer(testcase.config, d) if err != nil { t.Errorf("Unexpected error: %v", err) } if testcase.shouldError { f.Close() } e := f.EncodeAndPostData("tag_name", time.Unix(1482493046, 0), map[string]string{"foo": "bar"}) if testcase.shouldError { assert.Equal(t, fmt.Errorf("fluent#appendBuffer: Logger already closed"), e) } else { assert.Equal(t, nil, e) } }) } } func TestNoPanicOnAsyncMultipleClose(t *testing.T) { config := Config{ Async: true, } d := newTestDialer() f, err := newWithDialer(config, d) if err != nil { t.Errorf("Unexpected error: %v", err) } f.Close() f.Close() } func TestCloseOnFailingAsyncReconnect(t *testing.T) { testcases := map[string]Config{ "with RequestAck": { Async: true, ForceStopAsyncSend: true, RequestAck: true, }, "without RequestAck": { Async: true, ForceStopAsyncSend: true, RequestAck: false, }, } for tcname := range testcases { t.Run(tcname, func(t *testing.T) { tc := testcases[tcname] t.Parallel() d := newTestDialer() f, err := newWithDialer(tc, d) if err != nil { t.Errorf("Unexpected error: %v", err) } // Send a first message successfully. _ = f.EncodeAndPostData("tag_name", time.Unix(1482493046, 0), map[string]string{"foo": "bar"}) conn := d.waitForNextDialing(true, false) conn.waitForNextWrite(true, ackRespMsgp(t, "dgxdWAAAAAABAAAAAAAAAA==")) // Then try to send one during a transient connection failure. _ = f.EncodeAndPostData("tag_name", time.Unix(1482493046, 0), map[string]string{"bar": "baz"}) conn.waitForNextWrite(false, "") // And add some more logs to the log buffer. _ = f.EncodeAndPostData("tag_name", time.Unix(1482493046, 0), map[string]string{"acme": "corporation"}) // But close the logger before it got sent. This is expected to not block. timeout(t, 60*time.Second, func() { f.Close() }, "failed to close the logger") }) } } func TestCloseWhileWaitingForAckResponse(t *testing.T) { t.Parallel() d := newTestDialer() f, err := newWithDialer(Config{ Async: true, RequestAck: true, ForceStopAsyncSend: true, }, d) if err != nil { t.Errorf("Unexpected error: %v", err) } _ = f.EncodeAndPostData("tag_name", time.Unix(1482493046, 0), map[string]string{"foo": "bar"}) conn := d.waitForNextDialing(true, true) conn.waitForNextWrite(true, ackRespMsgp(t, "dgxdWAAAAAABAAAAAAAAAA==")) // Test if the logger can really by closed while the client waits for a ack message. timeout(t, 30*time.Second, func() { f.Close() }, "failed to close the logger") } func TestSyncWriteAfterCloseFails(t *testing.T) { d := newTestDialer() go func() { f, err := newWithDialer(Config{Async: false}, d) if err != nil { t.Errorf("Unexpected error: %v", err) } err = f.PostWithTime("tag_name", time.Unix(1482493046, 0), map[string]string{"foo": "bar"}) if err != nil { t.Errorf("Unexpected error: %v", err) } err = f.Close() if err != nil { t.Errorf("Unexpected error: %v", err) } // Now let's post some event after Fluent.Close(). err = f.PostWithTime("tag_name", time.Unix(1482493050, 0), map[string]string{"foo": "buzz"}) // The event submission must fail, assert.NotEqual(t, err, nil); // and also must keep Fluentd closed. assert.NotEqual(t, f.closed, false); }() conn := d.waitForNextDialing(true, false) conn.waitForNextWrite(true, "") } func Benchmark_PostWithShortMessage(b *testing.B) { b.StopTimer() d := newTestDialer() f, err := newWithDialer(Config{}, d) if err != nil { panic(err) } b.StartTimer() data := map[string]string{"message": "Hello World"} for i := 0; i < b.N; i++ { if err := f.Post("tag", data); err != nil { panic(err) } } } func Benchmark_PostWithShortMessageMarshalAsJSON(b *testing.B) { b.StopTimer() f, err := New(Config{MarshalAsJSON: true}) if err != nil { panic(err) } b.StartTimer() data := map[string]string{"message": "Hello World"} for i := 0; i < b.N; i++ { if err := f.Post("tag", data); err != nil { panic(err) } } } func Benchmark_LogWithChunks(b *testing.B) { b.StopTimer() f, err := New(Config{}) if err != nil { panic(err) } b.StartTimer() data := map[string]string{"msg": "sdfsdsdfdsfdsddddfsdfsdsdfdsfdsddddfsdfsdsdfdsfdsddddfsdfsdsdfdsfdsddddfsdfsdsdfdsfdsddddfsdfsdsdfdsfdsddddfsdfsdsdfdsfdsddddfsdfsdsdfdsfdsddddf"} for i := 0; i < b.N; i++ { if err := f.Post("tag", data); err != nil { panic(err) } } } func Benchmark_PostWithStruct(b *testing.B) { b.StopTimer() f, err := New(Config{}) if err != nil { panic(err) } b.StartTimer() data := struct { Name string `msg:"msgnamename"` }{ "john smith", } for i := 0; i < b.N; i++ { if err := f.Post("tag", data); err != nil { panic(err) } } } func Benchmark_PostWithStructTaggedAsCodec(b *testing.B) { b.StopTimer() f, err := New(Config{}) if err != nil { panic(err) } b.StartTimer() data := struct { Name string `codec:"codecname"` }{ "john smith", } for i := 0; i < b.N; i++ { if err := f.Post("tag", data); err != nil { panic(err) } } } func Benchmark_PostWithStructWithoutTag(b *testing.B) { b.StopTimer() f, err := New(Config{}) if err != nil { panic(err) } b.StartTimer() data := struct { Name string }{ "john smith", } for i := 0; i < b.N; i++ { if err := f.Post("tag", data); err != nil { panic(err) } } } func Benchmark_PostWithMapString(b *testing.B) { b.StopTimer() f, err := New(Config{}) if err != nil { panic(err) } b.StartTimer() data := map[string]string{ "foo": "bar", } for i := 0; i < b.N; i++ { if err := f.Post("tag", data); err != nil { panic(err) } } } func Benchmark_PostWithMsgpMarshaler(b *testing.B) { b.StopTimer() f, err := New(Config{}) if err != nil { panic(err) } b.StartTimer() data := &TestMessage{Foo: "bar"} for i := 0; i < b.N; i++ { if err := f.Post("tag", data); err != nil { panic(err) } } } func Benchmark_PostWithMapSlice(b *testing.B) { b.StopTimer() f, err := New(Config{}) if err != nil { panic(err) } b.StartTimer() data := map[string][]int{ "foo": {1, 2, 3}, } for i := 0; i < b.N; i++ { if err := f.Post("tag", data); err != nil { panic(err) } } } func Benchmark_PostWithMapStringAndTime(b *testing.B) { b.StopTimer() f, err := New(Config{}) if err != nil { panic(err) } b.StartTimer() data := map[string]string{ "foo": "bar", } tm := time.Now() for i := 0; i < b.N; i++ { if err := f.PostWithTime("tag", tm, data); err != nil { panic(err) } } } fluent-logger-golang-1.9.0/fluent/proto.go000066400000000000000000000053501416061525300205350ustar00rootroot00000000000000//go:generate msgp package fluent import ( "fmt" "time" "github.com/tinylib/msgp/msgp" ) //msgp:tuple Entry type Entry struct { Time int64 `msg:"time"` Record interface{} `msg:"record"` } //msgp:tuple Forward type Forward struct { Tag string `msg:"tag"` Entries []Entry `msg:"entries"` Option map[string]string } //msgp:tuple Message type Message struct { Tag string `msg:"tag"` Time int64 `msg:"time"` Record interface{} `msg:"record"` Option map[string]string } //msgp:tuple MessageExt type MessageExt struct { Tag string `msg:"tag"` Time EventTime `msg:"time,extension"` Record interface{} `msg:"record"` Option map[string]string } type AckResp struct { Ack string `json:"ack" msg:"ack"` } // EventTime is an extension to the serialized time value. It builds in support // for sub-second (nanosecond) precision in serialized timestamps. // // You can find the full specification for the msgpack message payload here: // https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1. // // You can find more information on msgpack extension types here: // https://github.com/tinylib/msgp/wiki/Using-Extensions. type EventTime time.Time const ( extensionType = 0 length = 8 ) func init() { msgp.RegisterExtension(extensionType, func() msgp.Extension { return new(EventTime) }) } func (t *EventTime) ExtensionType() int8 { return extensionType } func (t *EventTime) Len() int { return length } func (t *EventTime) MarshalBinaryTo(b []byte) error { // Unwrap to Golang time goTime := time.Time(*t) // There's no support for timezones in fluentd's protocol for EventTime. // Convert to UTC. utc := goTime.UTC() // Warning! Converting seconds to an int32 is a lossy operation. This code // will hit the "Year 2038" problem. sec := int32(utc.Unix()) nsec := utc.Nanosecond() // Fill the buffer with 4 bytes for the second component of the timestamp. b[0] = byte(sec >> 24) b[1] = byte(sec >> 16) b[2] = byte(sec >> 8) b[3] = byte(sec) // Fill the buffer with 4 bytes for the nanosecond component of the // timestamp. b[4] = byte(nsec >> 24) b[5] = byte(nsec >> 16) b[6] = byte(nsec >> 8) b[7] = byte(nsec) return nil } // Although decoding messages is not officially supported by this library, // UnmarshalBinary is implemented for testing and general completeness. func (t *EventTime) UnmarshalBinary(b []byte) error { if len(b) != length { return fmt.Errorf("Invalid EventTime byte length: %d", len(b)) } sec := (int32(b[0]) << 24) | (int32(b[1]) << 16) sec = sec | (int32(b[2]) << 8) | int32(b[3]) nsec := (int32(b[4]) << 24) | (int32(b[5]) << 16) nsec = nsec | (int32(b[6]) << 8) | int32(b[7]) *t = EventTime(time.Unix(int64(sec), int64(nsec))) return nil } fluent-logger-golang-1.9.0/fluent/proto_gen.go000066400000000000000000000447701416061525300213770ustar00rootroot00000000000000package fluent // Code generated by github.com/tinylib/msgp DO NOT EDIT. import ( "github.com/tinylib/msgp/msgp" ) // DecodeMsg implements msgp.Decodable func (z *AckResp) DecodeMsg(dc *msgp.Reader) (err error) { var field []byte _ = field var zb0001 uint32 zb0001, err = dc.ReadMapHeader() if err != nil { err = msgp.WrapError(err) return } for zb0001 > 0 { zb0001-- field, err = dc.ReadMapKeyPtr() if err != nil { err = msgp.WrapError(err) return } switch msgp.UnsafeString(field) { case "ack": z.Ack, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Ack") return } default: err = dc.Skip() if err != nil { err = msgp.WrapError(err) return } } } return } // EncodeMsg implements msgp.Encodable func (z AckResp) EncodeMsg(en *msgp.Writer) (err error) { // map header, size 1 // write "ack" err = en.Append(0x81, 0xa3, 0x61, 0x63, 0x6b) if err != nil { return } err = en.WriteString(z.Ack) if err != nil { err = msgp.WrapError(err, "Ack") return } return } // MarshalMsg implements msgp.Marshaler func (z AckResp) MarshalMsg(b []byte) (o []byte, err error) { o = msgp.Require(b, z.Msgsize()) // map header, size 1 // string "ack" o = append(o, 0x81, 0xa3, 0x61, 0x63, 0x6b) o = msgp.AppendString(o, z.Ack) return } // UnmarshalMsg implements msgp.Unmarshaler func (z *AckResp) UnmarshalMsg(bts []byte) (o []byte, err error) { var field []byte _ = field var zb0001 uint32 zb0001, bts, err = msgp.ReadMapHeaderBytes(bts) if err != nil { err = msgp.WrapError(err) return } for zb0001 > 0 { zb0001-- field, bts, err = msgp.ReadMapKeyZC(bts) if err != nil { err = msgp.WrapError(err) return } switch msgp.UnsafeString(field) { case "ack": z.Ack, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Ack") return } default: bts, err = msgp.Skip(bts) if err != nil { err = msgp.WrapError(err) return } } } o = bts return } // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z AckResp) Msgsize() (s int) { s = 1 + 4 + msgp.StringPrefixSize + len(z.Ack) return } // DecodeMsg implements msgp.Decodable func (z *Entry) DecodeMsg(dc *msgp.Reader) (err error) { var zb0001 uint32 zb0001, err = dc.ReadArrayHeader() if err != nil { err = msgp.WrapError(err) return } if zb0001 != 2 { err = msgp.ArrayError{Wanted: 2, Got: zb0001} return } z.Time, err = dc.ReadInt64() if err != nil { err = msgp.WrapError(err, "Time") return } z.Record, err = dc.ReadIntf() if err != nil { err = msgp.WrapError(err, "Record") return } return } // EncodeMsg implements msgp.Encodable func (z Entry) EncodeMsg(en *msgp.Writer) (err error) { // array header, size 2 err = en.Append(0x92) if err != nil { return } err = en.WriteInt64(z.Time) if err != nil { err = msgp.WrapError(err, "Time") return } err = en.WriteIntf(z.Record) if err != nil { err = msgp.WrapError(err, "Record") return } return } // MarshalMsg implements msgp.Marshaler func (z Entry) MarshalMsg(b []byte) (o []byte, err error) { o = msgp.Require(b, z.Msgsize()) // array header, size 2 o = append(o, 0x92) o = msgp.AppendInt64(o, z.Time) o, err = msgp.AppendIntf(o, z.Record) if err != nil { err = msgp.WrapError(err, "Record") return } return } // UnmarshalMsg implements msgp.Unmarshaler func (z *Entry) UnmarshalMsg(bts []byte) (o []byte, err error) { var zb0001 uint32 zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err) return } if zb0001 != 2 { err = msgp.ArrayError{Wanted: 2, Got: zb0001} return } z.Time, bts, err = msgp.ReadInt64Bytes(bts) if err != nil { err = msgp.WrapError(err, "Time") return } z.Record, bts, err = msgp.ReadIntfBytes(bts) if err != nil { err = msgp.WrapError(err, "Record") return } o = bts return } // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z Entry) Msgsize() (s int) { s = 1 + msgp.Int64Size + msgp.GuessSize(z.Record) return } // DecodeMsg implements msgp.Decodable func (z *Forward) DecodeMsg(dc *msgp.Reader) (err error) { var zb0001 uint32 zb0001, err = dc.ReadArrayHeader() if err != nil { err = msgp.WrapError(err) return } if zb0001 != 3 { err = msgp.ArrayError{Wanted: 3, Got: zb0001} return } z.Tag, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Tag") return } var zb0002 uint32 zb0002, err = dc.ReadArrayHeader() if err != nil { err = msgp.WrapError(err, "Entries") return } if cap(z.Entries) >= int(zb0002) { z.Entries = (z.Entries)[:zb0002] } else { z.Entries = make([]Entry, zb0002) } for za0001 := range z.Entries { var zb0003 uint32 zb0003, err = dc.ReadArrayHeader() if err != nil { err = msgp.WrapError(err, "Entries", za0001) return } if zb0003 != 2 { err = msgp.ArrayError{Wanted: 2, Got: zb0003} return } z.Entries[za0001].Time, err = dc.ReadInt64() if err != nil { err = msgp.WrapError(err, "Entries", za0001, "Time") return } z.Entries[za0001].Record, err = dc.ReadIntf() if err != nil { err = msgp.WrapError(err, "Entries", za0001, "Record") return } } var zb0004 uint32 zb0004, err = dc.ReadMapHeader() if err != nil { err = msgp.WrapError(err, "Option") return } if z.Option == nil { z.Option = make(map[string]string, zb0004) } else if len(z.Option) > 0 { for key := range z.Option { delete(z.Option, key) } } for zb0004 > 0 { zb0004-- var za0002 string var za0003 string za0002, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Option") return } za0003, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Option", za0002) return } z.Option[za0002] = za0003 } return } // EncodeMsg implements msgp.Encodable func (z *Forward) EncodeMsg(en *msgp.Writer) (err error) { // array header, size 3 err = en.Append(0x93) if err != nil { return } err = en.WriteString(z.Tag) if err != nil { err = msgp.WrapError(err, "Tag") return } err = en.WriteArrayHeader(uint32(len(z.Entries))) if err != nil { err = msgp.WrapError(err, "Entries") return } for za0001 := range z.Entries { // array header, size 2 err = en.Append(0x92) if err != nil { return } err = en.WriteInt64(z.Entries[za0001].Time) if err != nil { err = msgp.WrapError(err, "Entries", za0001, "Time") return } err = en.WriteIntf(z.Entries[za0001].Record) if err != nil { err = msgp.WrapError(err, "Entries", za0001, "Record") return } } err = en.WriteMapHeader(uint32(len(z.Option))) if err != nil { err = msgp.WrapError(err, "Option") return } for za0002, za0003 := range z.Option { err = en.WriteString(za0002) if err != nil { err = msgp.WrapError(err, "Option") return } err = en.WriteString(za0003) if err != nil { err = msgp.WrapError(err, "Option", za0002) return } } return } // MarshalMsg implements msgp.Marshaler func (z *Forward) MarshalMsg(b []byte) (o []byte, err error) { o = msgp.Require(b, z.Msgsize()) // array header, size 3 o = append(o, 0x93) o = msgp.AppendString(o, z.Tag) o = msgp.AppendArrayHeader(o, uint32(len(z.Entries))) for za0001 := range z.Entries { // array header, size 2 o = append(o, 0x92) o = msgp.AppendInt64(o, z.Entries[za0001].Time) o, err = msgp.AppendIntf(o, z.Entries[za0001].Record) if err != nil { err = msgp.WrapError(err, "Entries", za0001, "Record") return } } o = msgp.AppendMapHeader(o, uint32(len(z.Option))) for za0002, za0003 := range z.Option { o = msgp.AppendString(o, za0002) o = msgp.AppendString(o, za0003) } return } // UnmarshalMsg implements msgp.Unmarshaler func (z *Forward) UnmarshalMsg(bts []byte) (o []byte, err error) { var zb0001 uint32 zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err) return } if zb0001 != 3 { err = msgp.ArrayError{Wanted: 3, Got: zb0001} return } z.Tag, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Tag") return } var zb0002 uint32 zb0002, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "Entries") return } if cap(z.Entries) >= int(zb0002) { z.Entries = (z.Entries)[:zb0002] } else { z.Entries = make([]Entry, zb0002) } for za0001 := range z.Entries { var zb0003 uint32 zb0003, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "Entries", za0001) return } if zb0003 != 2 { err = msgp.ArrayError{Wanted: 2, Got: zb0003} return } z.Entries[za0001].Time, bts, err = msgp.ReadInt64Bytes(bts) if err != nil { err = msgp.WrapError(err, "Entries", za0001, "Time") return } z.Entries[za0001].Record, bts, err = msgp.ReadIntfBytes(bts) if err != nil { err = msgp.WrapError(err, "Entries", za0001, "Record") return } } var zb0004 uint32 zb0004, bts, err = msgp.ReadMapHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "Option") return } if z.Option == nil { z.Option = make(map[string]string, zb0004) } else if len(z.Option) > 0 { for key := range z.Option { delete(z.Option, key) } } for zb0004 > 0 { var za0002 string var za0003 string zb0004-- za0002, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Option") return } za0003, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Option", za0002) return } z.Option[za0002] = za0003 } o = bts return } // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *Forward) Msgsize() (s int) { s = 1 + msgp.StringPrefixSize + len(z.Tag) + msgp.ArrayHeaderSize for za0001 := range z.Entries { s += 1 + msgp.Int64Size + msgp.GuessSize(z.Entries[za0001].Record) } s += msgp.MapHeaderSize if z.Option != nil { for za0002, za0003 := range z.Option { _ = za0003 s += msgp.StringPrefixSize + len(za0002) + msgp.StringPrefixSize + len(za0003) } } return } // DecodeMsg implements msgp.Decodable func (z *Message) DecodeMsg(dc *msgp.Reader) (err error) { var zb0001 uint32 zb0001, err = dc.ReadArrayHeader() if err != nil { err = msgp.WrapError(err) return } if zb0001 != 4 { err = msgp.ArrayError{Wanted: 4, Got: zb0001} return } z.Tag, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Tag") return } z.Time, err = dc.ReadInt64() if err != nil { err = msgp.WrapError(err, "Time") return } z.Record, err = dc.ReadIntf() if err != nil { err = msgp.WrapError(err, "Record") return } var zb0002 uint32 zb0002, err = dc.ReadMapHeader() if err != nil { err = msgp.WrapError(err, "Option") return } if z.Option == nil { z.Option = make(map[string]string, zb0002) } else if len(z.Option) > 0 { for key := range z.Option { delete(z.Option, key) } } for zb0002 > 0 { zb0002-- var za0001 string var za0002 string za0001, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Option") return } za0002, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Option", za0001) return } z.Option[za0001] = za0002 } return } // EncodeMsg implements msgp.Encodable func (z *Message) EncodeMsg(en *msgp.Writer) (err error) { // array header, size 4 err = en.Append(0x94) if err != nil { return } err = en.WriteString(z.Tag) if err != nil { err = msgp.WrapError(err, "Tag") return } err = en.WriteInt64(z.Time) if err != nil { err = msgp.WrapError(err, "Time") return } err = en.WriteIntf(z.Record) if err != nil { err = msgp.WrapError(err, "Record") return } err = en.WriteMapHeader(uint32(len(z.Option))) if err != nil { err = msgp.WrapError(err, "Option") return } for za0001, za0002 := range z.Option { err = en.WriteString(za0001) if err != nil { err = msgp.WrapError(err, "Option") return } err = en.WriteString(za0002) if err != nil { err = msgp.WrapError(err, "Option", za0001) return } } return } // MarshalMsg implements msgp.Marshaler func (z *Message) MarshalMsg(b []byte) (o []byte, err error) { o = msgp.Require(b, z.Msgsize()) // array header, size 4 o = append(o, 0x94) o = msgp.AppendString(o, z.Tag) o = msgp.AppendInt64(o, z.Time) o, err = msgp.AppendIntf(o, z.Record) if err != nil { err = msgp.WrapError(err, "Record") return } o = msgp.AppendMapHeader(o, uint32(len(z.Option))) for za0001, za0002 := range z.Option { o = msgp.AppendString(o, za0001) o = msgp.AppendString(o, za0002) } return } // UnmarshalMsg implements msgp.Unmarshaler func (z *Message) UnmarshalMsg(bts []byte) (o []byte, err error) { var zb0001 uint32 zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err) return } if zb0001 != 4 { err = msgp.ArrayError{Wanted: 4, Got: zb0001} return } z.Tag, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Tag") return } z.Time, bts, err = msgp.ReadInt64Bytes(bts) if err != nil { err = msgp.WrapError(err, "Time") return } z.Record, bts, err = msgp.ReadIntfBytes(bts) if err != nil { err = msgp.WrapError(err, "Record") return } var zb0002 uint32 zb0002, bts, err = msgp.ReadMapHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "Option") return } if z.Option == nil { z.Option = make(map[string]string, zb0002) } else if len(z.Option) > 0 { for key := range z.Option { delete(z.Option, key) } } for zb0002 > 0 { var za0001 string var za0002 string zb0002-- za0001, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Option") return } za0002, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Option", za0001) return } z.Option[za0001] = za0002 } o = bts return } // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *Message) Msgsize() (s int) { s = 1 + msgp.StringPrefixSize + len(z.Tag) + msgp.Int64Size + msgp.GuessSize(z.Record) + msgp.MapHeaderSize if z.Option != nil { for za0001, za0002 := range z.Option { _ = za0002 s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002) } } return } // DecodeMsg implements msgp.Decodable func (z *MessageExt) DecodeMsg(dc *msgp.Reader) (err error) { var zb0001 uint32 zb0001, err = dc.ReadArrayHeader() if err != nil { err = msgp.WrapError(err) return } if zb0001 != 4 { err = msgp.ArrayError{Wanted: 4, Got: zb0001} return } z.Tag, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Tag") return } err = dc.ReadExtension(&z.Time) if err != nil { err = msgp.WrapError(err, "Time") return } z.Record, err = dc.ReadIntf() if err != nil { err = msgp.WrapError(err, "Record") return } var zb0002 uint32 zb0002, err = dc.ReadMapHeader() if err != nil { err = msgp.WrapError(err, "Option") return } if z.Option == nil { z.Option = make(map[string]string, zb0002) } else if len(z.Option) > 0 { for key := range z.Option { delete(z.Option, key) } } for zb0002 > 0 { zb0002-- var za0001 string var za0002 string za0001, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Option") return } za0002, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Option", za0001) return } z.Option[za0001] = za0002 } return } // EncodeMsg implements msgp.Encodable func (z *MessageExt) EncodeMsg(en *msgp.Writer) (err error) { // array header, size 4 err = en.Append(0x94) if err != nil { return } err = en.WriteString(z.Tag) if err != nil { err = msgp.WrapError(err, "Tag") return } err = en.WriteExtension(&z.Time) if err != nil { err = msgp.WrapError(err, "Time") return } err = en.WriteIntf(z.Record) if err != nil { err = msgp.WrapError(err, "Record") return } err = en.WriteMapHeader(uint32(len(z.Option))) if err != nil { err = msgp.WrapError(err, "Option") return } for za0001, za0002 := range z.Option { err = en.WriteString(za0001) if err != nil { err = msgp.WrapError(err, "Option") return } err = en.WriteString(za0002) if err != nil { err = msgp.WrapError(err, "Option", za0001) return } } return } // MarshalMsg implements msgp.Marshaler func (z *MessageExt) MarshalMsg(b []byte) (o []byte, err error) { o = msgp.Require(b, z.Msgsize()) // array header, size 4 o = append(o, 0x94) o = msgp.AppendString(o, z.Tag) o, err = msgp.AppendExtension(o, &z.Time) if err != nil { err = msgp.WrapError(err, "Time") return } o, err = msgp.AppendIntf(o, z.Record) if err != nil { err = msgp.WrapError(err, "Record") return } o = msgp.AppendMapHeader(o, uint32(len(z.Option))) for za0001, za0002 := range z.Option { o = msgp.AppendString(o, za0001) o = msgp.AppendString(o, za0002) } return } // UnmarshalMsg implements msgp.Unmarshaler func (z *MessageExt) UnmarshalMsg(bts []byte) (o []byte, err error) { var zb0001 uint32 zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err) return } if zb0001 != 4 { err = msgp.ArrayError{Wanted: 4, Got: zb0001} return } z.Tag, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Tag") return } bts, err = msgp.ReadExtensionBytes(bts, &z.Time) if err != nil { err = msgp.WrapError(err, "Time") return } z.Record, bts, err = msgp.ReadIntfBytes(bts) if err != nil { err = msgp.WrapError(err, "Record") return } var zb0002 uint32 zb0002, bts, err = msgp.ReadMapHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "Option") return } if z.Option == nil { z.Option = make(map[string]string, zb0002) } else if len(z.Option) > 0 { for key := range z.Option { delete(z.Option, key) } } for zb0002 > 0 { var za0001 string var za0002 string zb0002-- za0001, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Option") return } za0002, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Option", za0001) return } z.Option[za0001] = za0002 } o = bts return } // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *MessageExt) Msgsize() (s int) { s = 1 + msgp.StringPrefixSize + len(z.Tag) + msgp.ExtensionPrefixSize + z.Time.Len() + msgp.GuessSize(z.Record) + msgp.MapHeaderSize if z.Option != nil { for za0001, za0002 := range z.Option { _ = za0002 s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002) } } return } fluent-logger-golang-1.9.0/fluent/proto_gen_test.go000066400000000000000000000251031416061525300224230ustar00rootroot00000000000000package fluent // Code generated by github.com/tinylib/msgp DO NOT EDIT. import ( "bytes" "testing" "github.com/tinylib/msgp/msgp" ) func TestMarshalUnmarshalAckResp(t *testing.T) { v := AckResp{} bts, err := v.MarshalMsg(nil) if err != nil { t.Fatal(err) } left, err := v.UnmarshalMsg(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) } left, err = msgp.Skip(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after Skip(): %q", len(left), left) } } func BenchmarkMarshalMsgAckResp(b *testing.B) { v := AckResp{} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.MarshalMsg(nil) } } func BenchmarkAppendMsgAckResp(b *testing.B) { v := AckResp{} bts := make([]byte, 0, v.Msgsize()) bts, _ = v.MarshalMsg(bts[0:0]) b.SetBytes(int64(len(bts))) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { bts, _ = v.MarshalMsg(bts[0:0]) } } func BenchmarkUnmarshalAckResp(b *testing.B) { v := AckResp{} bts, _ := v.MarshalMsg(nil) b.ReportAllocs() b.SetBytes(int64(len(bts))) b.ResetTimer() for i := 0; i < b.N; i++ { _, err := v.UnmarshalMsg(bts) if err != nil { b.Fatal(err) } } } func TestEncodeDecodeAckResp(t *testing.T) { v := AckResp{} var buf bytes.Buffer msgp.Encode(&buf, &v) m := v.Msgsize() if buf.Len() > m { t.Logf("WARNING: Msgsize() for %v is inaccurate", v) } vn := AckResp{} err := msgp.Decode(&buf, &vn) if err != nil { t.Error(err) } buf.Reset() msgp.Encode(&buf, &v) err = msgp.NewReader(&buf).Skip() if err != nil { t.Error(err) } } func BenchmarkEncodeAckResp(b *testing.B) { v := AckResp{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) en := msgp.NewWriter(msgp.Nowhere) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.EncodeMsg(en) } en.Flush() } func BenchmarkDecodeAckResp(b *testing.B) { v := AckResp{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) rd := msgp.NewEndlessReader(buf.Bytes(), b) dc := msgp.NewReader(rd) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { err := v.DecodeMsg(dc) if err != nil { b.Fatal(err) } } } func TestMarshalUnmarshalEntry(t *testing.T) { v := Entry{} bts, err := v.MarshalMsg(nil) if err != nil { t.Fatal(err) } left, err := v.UnmarshalMsg(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) } left, err = msgp.Skip(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after Skip(): %q", len(left), left) } } func BenchmarkMarshalMsgEntry(b *testing.B) { v := Entry{} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.MarshalMsg(nil) } } func BenchmarkAppendMsgEntry(b *testing.B) { v := Entry{} bts := make([]byte, 0, v.Msgsize()) bts, _ = v.MarshalMsg(bts[0:0]) b.SetBytes(int64(len(bts))) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { bts, _ = v.MarshalMsg(bts[0:0]) } } func BenchmarkUnmarshalEntry(b *testing.B) { v := Entry{} bts, _ := v.MarshalMsg(nil) b.ReportAllocs() b.SetBytes(int64(len(bts))) b.ResetTimer() for i := 0; i < b.N; i++ { _, err := v.UnmarshalMsg(bts) if err != nil { b.Fatal(err) } } } func TestEncodeDecodeEntry(t *testing.T) { v := Entry{} var buf bytes.Buffer msgp.Encode(&buf, &v) m := v.Msgsize() if buf.Len() > m { t.Logf("WARNING: Msgsize() for %v is inaccurate", v) } vn := Entry{} err := msgp.Decode(&buf, &vn) if err != nil { t.Error(err) } buf.Reset() msgp.Encode(&buf, &v) err = msgp.NewReader(&buf).Skip() if err != nil { t.Error(err) } } func BenchmarkEncodeEntry(b *testing.B) { v := Entry{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) en := msgp.NewWriter(msgp.Nowhere) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.EncodeMsg(en) } en.Flush() } func BenchmarkDecodeEntry(b *testing.B) { v := Entry{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) rd := msgp.NewEndlessReader(buf.Bytes(), b) dc := msgp.NewReader(rd) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { err := v.DecodeMsg(dc) if err != nil { b.Fatal(err) } } } func TestMarshalUnmarshalForward(t *testing.T) { v := Forward{} bts, err := v.MarshalMsg(nil) if err != nil { t.Fatal(err) } left, err := v.UnmarshalMsg(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) } left, err = msgp.Skip(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after Skip(): %q", len(left), left) } } func BenchmarkMarshalMsgForward(b *testing.B) { v := Forward{} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.MarshalMsg(nil) } } func BenchmarkAppendMsgForward(b *testing.B) { v := Forward{} bts := make([]byte, 0, v.Msgsize()) bts, _ = v.MarshalMsg(bts[0:0]) b.SetBytes(int64(len(bts))) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { bts, _ = v.MarshalMsg(bts[0:0]) } } func BenchmarkUnmarshalForward(b *testing.B) { v := Forward{} bts, _ := v.MarshalMsg(nil) b.ReportAllocs() b.SetBytes(int64(len(bts))) b.ResetTimer() for i := 0; i < b.N; i++ { _, err := v.UnmarshalMsg(bts) if err != nil { b.Fatal(err) } } } func TestEncodeDecodeForward(t *testing.T) { v := Forward{} var buf bytes.Buffer msgp.Encode(&buf, &v) m := v.Msgsize() if buf.Len() > m { t.Logf("WARNING: Msgsize() for %v is inaccurate", v) } vn := Forward{} err := msgp.Decode(&buf, &vn) if err != nil { t.Error(err) } buf.Reset() msgp.Encode(&buf, &v) err = msgp.NewReader(&buf).Skip() if err != nil { t.Error(err) } } func BenchmarkEncodeForward(b *testing.B) { v := Forward{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) en := msgp.NewWriter(msgp.Nowhere) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.EncodeMsg(en) } en.Flush() } func BenchmarkDecodeForward(b *testing.B) { v := Forward{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) rd := msgp.NewEndlessReader(buf.Bytes(), b) dc := msgp.NewReader(rd) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { err := v.DecodeMsg(dc) if err != nil { b.Fatal(err) } } } func TestMarshalUnmarshalMessage(t *testing.T) { v := Message{} bts, err := v.MarshalMsg(nil) if err != nil { t.Fatal(err) } left, err := v.UnmarshalMsg(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) } left, err = msgp.Skip(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after Skip(): %q", len(left), left) } } func BenchmarkMarshalMsgMessage(b *testing.B) { v := Message{} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.MarshalMsg(nil) } } func BenchmarkAppendMsgMessage(b *testing.B) { v := Message{} bts := make([]byte, 0, v.Msgsize()) bts, _ = v.MarshalMsg(bts[0:0]) b.SetBytes(int64(len(bts))) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { bts, _ = v.MarshalMsg(bts[0:0]) } } func BenchmarkUnmarshalMessage(b *testing.B) { v := Message{} bts, _ := v.MarshalMsg(nil) b.ReportAllocs() b.SetBytes(int64(len(bts))) b.ResetTimer() for i := 0; i < b.N; i++ { _, err := v.UnmarshalMsg(bts) if err != nil { b.Fatal(err) } } } func TestEncodeDecodeMessage(t *testing.T) { v := Message{} var buf bytes.Buffer msgp.Encode(&buf, &v) m := v.Msgsize() if buf.Len() > m { t.Logf("WARNING: Msgsize() for %v is inaccurate", v) } vn := Message{} err := msgp.Decode(&buf, &vn) if err != nil { t.Error(err) } buf.Reset() msgp.Encode(&buf, &v) err = msgp.NewReader(&buf).Skip() if err != nil { t.Error(err) } } func BenchmarkEncodeMessage(b *testing.B) { v := Message{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) en := msgp.NewWriter(msgp.Nowhere) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.EncodeMsg(en) } en.Flush() } func BenchmarkDecodeMessage(b *testing.B) { v := Message{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) rd := msgp.NewEndlessReader(buf.Bytes(), b) dc := msgp.NewReader(rd) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { err := v.DecodeMsg(dc) if err != nil { b.Fatal(err) } } } func TestMarshalUnmarshalMessageExt(t *testing.T) { v := MessageExt{} bts, err := v.MarshalMsg(nil) if err != nil { t.Fatal(err) } left, err := v.UnmarshalMsg(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) } left, err = msgp.Skip(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after Skip(): %q", len(left), left) } } func BenchmarkMarshalMsgMessageExt(b *testing.B) { v := MessageExt{} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.MarshalMsg(nil) } } func BenchmarkAppendMsgMessageExt(b *testing.B) { v := MessageExt{} bts := make([]byte, 0, v.Msgsize()) bts, _ = v.MarshalMsg(bts[0:0]) b.SetBytes(int64(len(bts))) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { bts, _ = v.MarshalMsg(bts[0:0]) } } func BenchmarkUnmarshalMessageExt(b *testing.B) { v := MessageExt{} bts, _ := v.MarshalMsg(nil) b.ReportAllocs() b.SetBytes(int64(len(bts))) b.ResetTimer() for i := 0; i < b.N; i++ { _, err := v.UnmarshalMsg(bts) if err != nil { b.Fatal(err) } } } func TestEncodeDecodeMessageExt(t *testing.T) { v := MessageExt{} var buf bytes.Buffer msgp.Encode(&buf, &v) m := v.Msgsize() if buf.Len() > m { t.Logf("WARNING: Msgsize() for %v is inaccurate", v) } vn := MessageExt{} err := msgp.Decode(&buf, &vn) if err != nil { t.Error(err) } buf.Reset() msgp.Encode(&buf, &v) err = msgp.NewReader(&buf).Skip() if err != nil { t.Error(err) } } func BenchmarkEncodeMessageExt(b *testing.B) { v := MessageExt{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) en := msgp.NewWriter(msgp.Nowhere) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.EncodeMsg(en) } en.Flush() } func BenchmarkDecodeMessageExt(b *testing.B) { v := MessageExt{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) rd := msgp.NewEndlessReader(buf.Bytes(), b) dc := msgp.NewReader(rd) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { err := v.DecodeMsg(dc) if err != nil { b.Fatal(err) } } } fluent-logger-golang-1.9.0/fluent/test_message.go000066400000000000000000000002351416061525300220520ustar00rootroot00000000000000package fluent //go:generate msgp type TestMessage struct { Foo string `msg:"foo" json:"foo,omitempty"` Hoge string `msg:"hoge" json:"hoge,omitempty"` } fluent-logger-golang-1.9.0/fluent/test_message_gen.go000066400000000000000000000054131416061525300227060ustar00rootroot00000000000000package fluent // Code generated by github.com/tinylib/msgp DO NOT EDIT. import ( "github.com/tinylib/msgp/msgp" ) // DecodeMsg implements msgp.Decodable func (z *TestMessage) DecodeMsg(dc *msgp.Reader) (err error) { var field []byte _ = field var zb0001 uint32 zb0001, err = dc.ReadMapHeader() if err != nil { err = msgp.WrapError(err) return } for zb0001 > 0 { zb0001-- field, err = dc.ReadMapKeyPtr() if err != nil { err = msgp.WrapError(err) return } switch msgp.UnsafeString(field) { case "foo": z.Foo, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Foo") return } case "hoge": z.Hoge, err = dc.ReadString() if err != nil { err = msgp.WrapError(err, "Hoge") return } default: err = dc.Skip() if err != nil { err = msgp.WrapError(err) return } } } return } // EncodeMsg implements msgp.Encodable func (z TestMessage) EncodeMsg(en *msgp.Writer) (err error) { // map header, size 2 // write "foo" err = en.Append(0x82, 0xa3, 0x66, 0x6f, 0x6f) if err != nil { return } err = en.WriteString(z.Foo) if err != nil { err = msgp.WrapError(err, "Foo") return } // write "hoge" err = en.Append(0xa4, 0x68, 0x6f, 0x67, 0x65) if err != nil { return } err = en.WriteString(z.Hoge) if err != nil { err = msgp.WrapError(err, "Hoge") return } return } // MarshalMsg implements msgp.Marshaler func (z TestMessage) MarshalMsg(b []byte) (o []byte, err error) { o = msgp.Require(b, z.Msgsize()) // map header, size 2 // string "foo" o = append(o, 0x82, 0xa3, 0x66, 0x6f, 0x6f) o = msgp.AppendString(o, z.Foo) // string "hoge" o = append(o, 0xa4, 0x68, 0x6f, 0x67, 0x65) o = msgp.AppendString(o, z.Hoge) return } // UnmarshalMsg implements msgp.Unmarshaler func (z *TestMessage) UnmarshalMsg(bts []byte) (o []byte, err error) { var field []byte _ = field var zb0001 uint32 zb0001, bts, err = msgp.ReadMapHeaderBytes(bts) if err != nil { err = msgp.WrapError(err) return } for zb0001 > 0 { zb0001-- field, bts, err = msgp.ReadMapKeyZC(bts) if err != nil { err = msgp.WrapError(err) return } switch msgp.UnsafeString(field) { case "foo": z.Foo, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Foo") return } case "hoge": z.Hoge, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Hoge") return } default: bts, err = msgp.Skip(bts) if err != nil { err = msgp.WrapError(err) return } } } o = bts return } // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z TestMessage) Msgsize() (s int) { s = 1 + 4 + msgp.StringPrefixSize + len(z.Foo) + 5 + msgp.StringPrefixSize + len(z.Hoge) return } fluent-logger-golang-1.9.0/fluent/test_message_gen_test.go000066400000000000000000000044341416061525300237470ustar00rootroot00000000000000package fluent // Code generated by github.com/tinylib/msgp DO NOT EDIT. import ( "bytes" "testing" "github.com/tinylib/msgp/msgp" ) func TestMarshalUnmarshalTestMessage(t *testing.T) { v := TestMessage{} bts, err := v.MarshalMsg(nil) if err != nil { t.Fatal(err) } left, err := v.UnmarshalMsg(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) } left, err = msgp.Skip(bts) if err != nil { t.Fatal(err) } if len(left) > 0 { t.Errorf("%d bytes left over after Skip(): %q", len(left), left) } } func BenchmarkMarshalMsgTestMessage(b *testing.B) { v := TestMessage{} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.MarshalMsg(nil) } } func BenchmarkAppendMsgTestMessage(b *testing.B) { v := TestMessage{} bts := make([]byte, 0, v.Msgsize()) bts, _ = v.MarshalMsg(bts[0:0]) b.SetBytes(int64(len(bts))) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { bts, _ = v.MarshalMsg(bts[0:0]) } } func BenchmarkUnmarshalTestMessage(b *testing.B) { v := TestMessage{} bts, _ := v.MarshalMsg(nil) b.ReportAllocs() b.SetBytes(int64(len(bts))) b.ResetTimer() for i := 0; i < b.N; i++ { _, err := v.UnmarshalMsg(bts) if err != nil { b.Fatal(err) } } } func TestEncodeDecodeTestMessage(t *testing.T) { v := TestMessage{} var buf bytes.Buffer msgp.Encode(&buf, &v) m := v.Msgsize() if buf.Len() > m { t.Logf("WARNING: Msgsize() for %v is inaccurate", v) } vn := TestMessage{} err := msgp.Decode(&buf, &vn) if err != nil { t.Error(err) } buf.Reset() msgp.Encode(&buf, &v) err = msgp.NewReader(&buf).Skip() if err != nil { t.Error(err) } } func BenchmarkEncodeTestMessage(b *testing.B) { v := TestMessage{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) en := msgp.NewWriter(msgp.Nowhere) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { v.EncodeMsg(en) } en.Flush() } func BenchmarkDecodeTestMessage(b *testing.B) { v := TestMessage{} var buf bytes.Buffer msgp.Encode(&buf, &v) b.SetBytes(int64(buf.Len())) rd := msgp.NewEndlessReader(buf.Bytes(), b) dc := msgp.NewReader(rd) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { err := v.DecodeMsg(dc) if err != nil { b.Fatal(err) } } } fluent-logger-golang-1.9.0/fluent/testdata/000077500000000000000000000000001416061525300206515ustar00rootroot00000000000000fluent-logger-golang-1.9.0/fluent/testdata/config.json000066400000000000000000000005111416061525300230060ustar00rootroot00000000000000{ "fluent_port":8888, "fluent_host":"localhost", "fluent_network":"tcp", "fluent_socket_path":"/var/tmp/fluent.sock", "timeout":3000, "write_timeout":6000, "buffer_limit":10, "retry_wait":5, "max_retry":3, "tag_prefix":"fluent", "async": false, "force_stop_async_send": false, "marshal_as_json": true } fluent-logger-golang-1.9.0/fluent/version.go000066400000000000000000000000501416061525300210470ustar00rootroot00000000000000package fluent const Version = "1.9.0"