| 
									
										
										
										
											2021-04-19 03:41:13 +08:00
										 |  |  | // Copyright (c) 2015-2021 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | package http | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2019-07-03 13:34:32 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2023-02-22 13:19:46 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2019-10-12 09:50:54 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 	"sync/atomic" | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2019-02-07 04:07:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	xhttp "github.com/minio/minio/internal/http" | 
					
						
							| 
									
										
										
										
											2022-02-25 01:05:33 +08:00
										 |  |  | 	"github.com/minio/minio/internal/logger/target/types" | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	// Timeout for the webhook http call
 | 
					
						
							|  |  |  | 	webhookCallTimeout = 5 * time.Second | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// maxWorkers is the maximum number of concurrent operations.
 | 
					
						
							|  |  |  | 	maxWorkers = 8 | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2021-05-28 00:54:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | // Config http logger target
 | 
					
						
							|  |  |  | type Config struct { | 
					
						
							|  |  |  | 	Enabled    bool              `json:"enabled"` | 
					
						
							|  |  |  | 	Name       string            `json:"name"` | 
					
						
							|  |  |  | 	UserAgent  string            `json:"userAgent"` | 
					
						
							|  |  |  | 	Endpoint   string            `json:"endpoint"` | 
					
						
							|  |  |  | 	AuthToken  string            `json:"authToken"` | 
					
						
							|  |  |  | 	ClientCert string            `json:"clientCert"` | 
					
						
							|  |  |  | 	ClientKey  string            `json:"clientKey"` | 
					
						
							| 
									
										
										
										
											2021-12-21 05:16:53 +08:00
										 |  |  | 	QueueSize  int               `json:"queueSize"` | 
					
						
							| 
									
										
										
										
											2023-02-22 13:19:46 +08:00
										 |  |  | 	Proxy      string            `json:"string"` | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 	Transport  http.RoundTripper `json:"-"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Custom logger
 | 
					
						
							| 
									
										
										
										
											2022-07-28 00:44:59 +08:00
										 |  |  | 	LogOnce func(ctx context.Context, err error, id string, errKind ...interface{}) `json:"-"` | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | // Target implements logger.Target and sends the json
 | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | // format of a log entry to the configured http endpoint.
 | 
					
						
							|  |  |  | // An internal buffer of logs is maintained but when the
 | 
					
						
							|  |  |  | // buffer is full, new logs are just ignored and an error
 | 
					
						
							|  |  |  | // is returned to the caller.
 | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | type Target struct { | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 	totalMessages  int64 | 
					
						
							|  |  |  | 	failedMessages int64 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Worker control
 | 
					
						
							|  |  |  | 	workers       int64 | 
					
						
							|  |  |  | 	workerStartMu sync.Mutex | 
					
						
							|  |  |  | 	lastStarted   time.Time | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 	wg     sync.WaitGroup | 
					
						
							| 
									
										
										
										
											2022-05-17 07:10:51 +08:00
										 |  |  | 	doneCh chan struct{} | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 	// Channel of log entries
 | 
					
						
							| 
									
										
										
										
											2018-10-13 03:25:59 +08:00
										 |  |  | 	logCh chan interface{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 00:03:26 +08:00
										 |  |  | 	// is the target online?
 | 
					
						
							|  |  |  | 	online bool | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 	config Config | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 	client *http.Client | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-03 07:19:44 +08:00
										 |  |  | // Endpoint returns the backend endpoint
 | 
					
						
							|  |  |  | func (h *Target) Endpoint() string { | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 	return h.config.Endpoint | 
					
						
							| 
									
										
										
										
											2020-10-03 07:19:44 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *Target) String() string { | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 	return h.config.Name | 
					
						
							| 
									
										
										
										
											2020-10-03 07:19:44 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 00:03:26 +08:00
										 |  |  | // IsOnline returns true if the initialization was successful
 | 
					
						
							|  |  |  | func (h *Target) IsOnline() bool { | 
					
						
							|  |  |  | 	return h.online | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | // Stats returns the target statistics.
 | 
					
						
							|  |  |  | func (h *Target) Stats() types.TargetStats { | 
					
						
							|  |  |  | 	return types.TargetStats{ | 
					
						
							|  |  |  | 		TotalMessages:  atomic.LoadInt64(&h.totalMessages), | 
					
						
							|  |  |  | 		FailedMessages: atomic.LoadInt64(&h.failedMessages), | 
					
						
							|  |  |  | 		QueueLength:    len(h.logCh), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | // Init validate and initialize the http target
 | 
					
						
							|  |  |  | func (h *Target) Init() error { | 
					
						
							| 
									
										
										
										
											2021-05-28 00:54:10 +08:00
										 |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), 2*webhookCallTimeout) | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 	req, err := http.NewRequestWithContext(ctx, http.MethodPost, h.config.Endpoint, strings.NewReader(`{}`)) | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req.Header.Set(xhttp.ContentType, "application/json") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set user-agent to indicate MinIO release
 | 
					
						
							|  |  |  | 	// version to the configured log endpoint
 | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 	req.Header.Set("User-Agent", h.config.UserAgent) | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 	if h.config.AuthToken != "" { | 
					
						
							|  |  |  | 		req.Header.Set("Authorization", h.config.AuthToken) | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 13:19:46 +08:00
										 |  |  | 	// If proxy available, set the same
 | 
					
						
							|  |  |  | 	if h.config.Proxy != "" { | 
					
						
							|  |  |  | 		proxyURL, _ := url.Parse(h.config.Proxy) | 
					
						
							|  |  |  | 		transport := h.config.Transport | 
					
						
							|  |  |  | 		ctransport := transport.(*http.Transport).Clone() | 
					
						
							|  |  |  | 		ctransport.Proxy = http.ProxyURL(proxyURL) | 
					
						
							|  |  |  | 		h.config.Transport = ctransport | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 	client := http.Client{Transport: h.config.Transport} | 
					
						
							|  |  |  | 	resp, err := client.Do(req) | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 	h.client = &client | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Drain any response.
 | 
					
						
							|  |  |  | 	xhttp.DrainBody(resp.Body) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-11 05:27:37 +08:00
										 |  |  | 	if !acceptedResponseStatusCode(resp.StatusCode) { | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 		switch resp.StatusCode { | 
					
						
							|  |  |  | 		case http.StatusForbidden: | 
					
						
							|  |  |  | 			return fmt.Errorf("%s returned '%s', please check if your auth token is correctly set", | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 				h.config.Endpoint, resp.Status) | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return fmt.Errorf("%s returned '%s', please check your endpoint configuration", | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 			h.config.Endpoint, resp.Status) | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 	h.lastStarted = time.Now() | 
					
						
							| 
									
										
										
										
											2022-11-29 00:03:26 +08:00
										 |  |  | 	h.online = true | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 	atomic.AddInt64(&h.workers, 1) | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 	go h.startHTTPLogger() | 
					
						
							| 
									
										
										
										
											2020-08-17 01:25:00 +08:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-11 05:27:37 +08:00
										 |  |  | // Accepted HTTP Status Codes
 | 
					
						
							|  |  |  | var acceptedStatusCodeMap = map[int]bool{http.StatusOK: true, http.StatusCreated: true, http.StatusAccepted: true, http.StatusNoContent: true} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func acceptedResponseStatusCode(code int) bool { | 
					
						
							|  |  |  | 	return acceptedStatusCodeMap[code] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | func (h *Target) logEntry(entry interface{}) { | 
					
						
							|  |  |  | 	logJSON, err := json.Marshal(&entry) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 		atomic.AddInt64(&h.failedMessages, 1) | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), webhookCallTimeout) | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 	defer cancel() | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 	req, err := http.NewRequestWithContext(ctx, http.MethodPost, | 
					
						
							|  |  |  | 		h.config.Endpoint, bytes.NewReader(logJSON)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		h.config.LogOnce(ctx, fmt.Errorf("%s returned '%w', please check your endpoint configuration", h.config.Endpoint, err), h.config.Endpoint) | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 		atomic.AddInt64(&h.failedMessages, 1) | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	req.Header.Set(xhttp.ContentType, "application/json") | 
					
						
							| 
									
										
										
										
											2022-02-24 05:36:01 +08:00
										 |  |  | 	req.Header.Set(xhttp.MinIOVersion, xhttp.GlobalMinIOVersion) | 
					
						
							|  |  |  | 	req.Header.Set(xhttp.MinioDeploymentID, xhttp.GlobalDeploymentID) | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Set user-agent to indicate MinIO release
 | 
					
						
							|  |  |  | 	// version to the configured log endpoint
 | 
					
						
							|  |  |  | 	req.Header.Set("User-Agent", h.config.UserAgent) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if h.config.AuthToken != "" { | 
					
						
							|  |  |  | 		req.Header.Set("Authorization", h.config.AuthToken) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 	resp, err := h.client.Do(req) | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 		atomic.AddInt64(&h.failedMessages, 1) | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 		h.config.LogOnce(ctx, fmt.Errorf("%s returned '%w', please check your endpoint configuration", h.config.Endpoint, err), h.config.Endpoint) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Drain any response.
 | 
					
						
							|  |  |  | 	xhttp.DrainBody(resp.Body) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !acceptedResponseStatusCode(resp.StatusCode) { | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 		atomic.AddInt64(&h.failedMessages, 1) | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 		switch resp.StatusCode { | 
					
						
							|  |  |  | 		case http.StatusForbidden: | 
					
						
							|  |  |  | 			h.config.LogOnce(ctx, fmt.Errorf("%s returned '%s', please check if your auth token is correctly set", h.config.Endpoint, resp.Status), h.config.Endpoint) | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			h.config.LogOnce(ctx, fmt.Errorf("%s returned '%s', please check your endpoint configuration", h.config.Endpoint, resp.Status), h.config.Endpoint) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | func (h *Target) startHTTPLogger() { | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 	// Create a routine which sends json logs received
 | 
					
						
							|  |  |  | 	// from an internal channel.
 | 
					
						
							| 
									
										
										
										
											2022-05-17 07:10:51 +08:00
										 |  |  | 	h.wg.Add(1) | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 	go func() { | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 		defer func() { | 
					
						
							|  |  |  | 			h.wg.Done() | 
					
						
							|  |  |  | 			atomic.AddInt64(&h.workers, -1) | 
					
						
							|  |  |  | 		}() | 
					
						
							| 
									
										
										
										
											2022-05-17 07:10:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-17 22:43:25 +08:00
										 |  |  | 		for { | 
					
						
							|  |  |  | 			select { | 
					
						
							|  |  |  | 			case entry := <-h.logCh: | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 				atomic.AddInt64(&h.totalMessages, 1) | 
					
						
							| 
									
										
										
										
											2022-05-17 22:43:25 +08:00
										 |  |  | 				h.logEntry(entry) | 
					
						
							|  |  |  | 			case <-h.doneCh: | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | // New initializes a new logger target which
 | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | // sends log over http to the specified endpoint
 | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | func New(config Config) *Target { | 
					
						
							| 
									
										
										
										
											2020-04-02 11:53:07 +08:00
										 |  |  | 	h := &Target{ | 
					
						
							| 
									
										
										
										
											2021-12-21 05:16:53 +08:00
										 |  |  | 		logCh:  make(chan interface{}, config.QueueSize), | 
					
						
							| 
									
										
										
										
											2022-05-17 07:10:51 +08:00
										 |  |  | 		doneCh: make(chan struct{}), | 
					
						
							| 
									
										
										
										
											2021-07-14 00:39:13 +08:00
										 |  |  | 		config: config, | 
					
						
							| 
									
										
										
										
											2022-11-29 00:03:26 +08:00
										 |  |  | 		online: false, | 
					
						
							| 
									
										
										
										
											2020-04-02 11:53:07 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return h | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | // Send log message 'e' to http target.
 | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | func (h *Target) Send(entry interface{}) error { | 
					
						
							| 
									
										
										
										
											2022-11-29 00:03:26 +08:00
										 |  |  | 	if !h.online { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-17 07:10:51 +08:00
										 |  |  | 	select { | 
					
						
							|  |  |  | 	case <-h.doneCh: | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2022-05-17 07:10:51 +08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 	select { | 
					
						
							| 
									
										
										
										
											2022-05-17 07:10:51 +08:00
										 |  |  | 	case <-h.doneCh: | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 	case h.logCh <- entry: | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 		nWorkers := atomic.LoadInt64(&h.workers) | 
					
						
							|  |  |  | 		if nWorkers < maxWorkers { | 
					
						
							|  |  |  | 			// Only have one try to start at the same time.
 | 
					
						
							|  |  |  | 			h.workerStartMu.Lock() | 
					
						
							|  |  |  | 			defer h.workerStartMu.Unlock() | 
					
						
							|  |  |  | 			// Start one max every second.
 | 
					
						
							|  |  |  | 			if time.Since(h.lastStarted) > time.Second { | 
					
						
							|  |  |  | 				if atomic.CompareAndSwapInt64(&h.workers, nWorkers, nWorkers+1) { | 
					
						
							|  |  |  | 					// Start another logger.
 | 
					
						
							|  |  |  | 					h.lastStarted = time.Now() | 
					
						
							|  |  |  | 					go h.startHTTPLogger() | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// Block to send
 | 
					
						
							|  |  |  | 			select { | 
					
						
							|  |  |  | 			case <-h.doneCh: | 
					
						
							|  |  |  | 			case h.logCh <- entry: | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 		// log channel is full, do not wait and return
 | 
					
						
							|  |  |  | 		// an error immediately to the caller
 | 
					
						
							| 
									
										
										
										
											2022-11-11 02:20:21 +08:00
										 |  |  | 		atomic.AddInt64(&h.totalMessages, 1) | 
					
						
							|  |  |  | 		atomic.AddInt64(&h.failedMessages, 1) | 
					
						
							| 
									
										
										
										
											2018-07-20 06:55:06 +08:00
										 |  |  | 		return errors.New("log buffer full") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Cancel - cancels the target
 | 
					
						
							|  |  |  | func (h *Target) Cancel() { | 
					
						
							| 
									
										
										
										
											2022-05-17 07:10:51 +08:00
										 |  |  | 	close(h.doneCh) | 
					
						
							|  |  |  | 	close(h.logCh) | 
					
						
							| 
									
										
										
										
											2022-02-18 03:11:15 +08:00
										 |  |  | 	h.wg.Wait() | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-02-25 01:05:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Type - returns type of the target
 | 
					
						
							|  |  |  | func (h *Target) Type() types.TargetType { | 
					
						
							|  |  |  | 	return types.TargetHTTP | 
					
						
							|  |  |  | } |