diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 70fb482d600..ebc37f6a623 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -12,7 +12,7 @@ on: jobs: changelog: runs-on: ubuntu-latest - if: ${{ !contains(github.event.pull_request.labels.*.name, 'dependencies') && !contains(github.event.pull_request.labels.*.name, 'Skip Changelog')}} + if: ${{ !contains(github.event.pull_request.labels.*.name, 'dependencies') && !contains(github.event.pull_request.labels.*.name, 'Skip Changelog') && !contains(github.event.pull_request.title, '[chore]')}} steps: - uses: actions/checkout@v3 @@ -28,6 +28,6 @@ jobs: echo "A CHANGELOG was modified. Looks good!" else echo "No CHANGELOG was modified." - echo "Please add a CHANGELOG entry, or add the \"Skip Changelog\" label if not required." + echo "Please add a CHANGELOG entry, or add either \"[chore]\" to the title of the pull request or add the \"Skip Changelog\" label if not required." false fi diff --git a/.github/workflows/scripts/dependabot-pr.sh b/.github/workflows/scripts/dependabot-pr.sh index 0d6daa35815..8ab0fcab931 100755 --- a/.github/workflows/scripts/dependabot-pr.sh +++ b/.github/workflows/scripts/dependabot-pr.sh @@ -41,4 +41,4 @@ git commit -m "dependabot updates `date` $message" git push origin $PR_NAME -gh pr create --title "dependabot updates `date`" --body "$message" -l "Skip Changelog" +gh pr create --title "[chore] dependabot updates `date`" --body "$message" -l "Skip Changelog" diff --git a/.golangci.yml b/.golangci.yml index c10e571dbed..01702fdd710 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -134,6 +134,10 @@ issues: - text: "G402:" linters: - gosec + # https://github.com/open-telemetry/opentelemetry-collector/issues/5699 + - text: "G112:" + linters: + - gosec # The list of ids of default excludes to include or disable. By default it's empty. # See the list of default excludes here https://golangci-lint.run/usage/configuration. diff --git a/CHANGELOG.md b/CHANGELOG.md index 898f1c4a2f3..db981f7a6e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,14 @@ - Add `linux-ppc64le` architecture to cross build tests in CI - `client`: perform case insensitive lookups in case the requested metadata value isn't found (#5646) - `loggingexporter`: Decouple `loglevel` field from level of logged messages (#5678) +- Expose `pcommon.NewSliceFromRaw` function (#5679) +- `loggingexporter`: create the exporter's logger from the service's logger (#5677) ### 🧰 Bug fixes 🧰 - Fix Collector panic when disabling telemetry metrics (#5642) - Fix Collector panic when featuregate value is empty (#5663) +- Fix confighttp.compression panic due to nil request.Body. (#5628) ## v0.55.0 Beta diff --git a/Makefile b/Makefile index c05f41912a4..a5315964189 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ TOOLS_MOD_DIR := ./internal/tools GOOS=$(shell $(GOCMD) env GOOS) GOARCH=$(shell $(GOCMD) env GOARCH) +GH := $(shell which gh) # TODO: Find a way to configure this in the generated code, currently no effect. BUILD_INFO_IMPORT_PATH=go.opentelemetry.io/collector/internal/version @@ -369,3 +370,46 @@ multimod-verify: install-tools multimod-prerelease: install-tools multimod prerelease -v ./versions.yaml -m collector-core $(MAKE) gotidy + +.PHONY: prepare-release +prepare-release: +ifdef PREVIOUS_VERSION + @echo "Previous version $(PREVIOUS_VERSION)" +else + @echo "PREVIOUS_VERSION not defined" + @echo "usage: make prepare-release RELEASE_CANDIDATE= PREVIOUS_VERSION=" + exit 1 +endif +ifdef RELEASE_CANDIDATE + @echo "Preparing release $(RELEASE_CANDIDATE)" +else + @echo "RELEASE_CANDIDATE not defined" + @echo "usage: make prepare-release RELEASE_CANDIDATE= PREVIOUS_VERSION=" + exit 1 +endif + # ensure a clean branch + git diff -s --exit-code || (echo "local repository not clean"; exit 1) + # TODO: update changelog + # update versions.yaml config.go builder-config.yaml + sed -i.bak 's/$(PREVIOUS_VERSION)/$(RELEASE_CANDIDATE)/g' versions.yaml + sed -i.bak 's/$(PREVIOUS_VERSION)/$(RELEASE_CANDIDATE)/g' ./cmd/builder/internal/builder/config.go + sed -i.bak 's/$(PREVIOUS_VERSION)/$(RELEASE_CANDIDATE)/g' ./cmd/otelcorecol/builder-config.yaml + sed -i.bak 's/$(PREVIOUS_VERSION)/$(RELEASE_CANDIDATE)/g' examples/k8s/otel-config.yaml + find . -name "*.bak" -type f -delete + # regenerate files + $(MAKE) genotelcorecol + # commit changes before running multimod + git checkout -b opentelemetry-collector-bot/release-$(RELEASE_CANDIDATE) + git add . + git commit -m "prepare release $(RELEASE_CANDIDATE)" + $(MAKE) multimod-prerelease + # commit multimod changes + git add . + git commit -m "add multimod changes" || (echo "no multimod changes to commit") + git push fork opentelemetry-collector-bot/release-$(RELEASE_CANDIDATE) + @if [ -z "$(GH)" ]; then \ + echo "'gh' command not found, can't submit the PR on your behalf."; \ + exit 1; \ + fi + gh pr create --title "[chore] prepare release $(RELEASE_CANDIDATE)" + diff --git a/config/confighttp/compression.go b/config/confighttp/compression.go index 13537d599f1..e85b2cfa90c 100644 --- a/config/confighttp/compression.go +++ b/config/confighttp/compression.go @@ -82,19 +82,21 @@ func (r *compressRoundTripper) RoundTrip(req *http.Request) (*http.Response, err if writerErr != nil { return nil, writerErr } - _, copyErr := io.Copy(compressWriter, req.Body) - closeErr := req.Body.Close() + if req.Body != nil { + _, copyErr := io.Copy(compressWriter, req.Body) + closeErr := req.Body.Close() - if err := compressWriter.Close(); err != nil { - return nil, err - } + if copyErr != nil { + return nil, copyErr + } - if copyErr != nil { - return nil, copyErr + if closeErr != nil { + return nil, closeErr + } } - if closeErr != nil { - return nil, closeErr + if err := compressWriter.Close(); err != nil { + return nil, err } // Create a new request since the docs say that we cannot modify the "req" diff --git a/config/confighttp/compression_test.go b/config/confighttp/compression_test.go index 9a477559a2e..c5fc726f9d4 100644 --- a/config/confighttp/compression_test.go +++ b/config/confighttp/compression_test.go @@ -19,9 +19,12 @@ import ( "compress/gzip" "compress/zlib" "fmt" + "io" "io/ioutil" "net" "net/http" + "net/http/httptest" + "net/url" "testing" "time" @@ -233,6 +236,85 @@ func TestHTTPContentDecompressionHandler(t *testing.T) { } } +func TestHTTPContentCompressionRequestWithNilBody(t *testing.T) { + compressedGzipBody, _ := compressGzip([]byte{}) + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + body, err := ioutil.ReadAll(r.Body) + require.NoError(t, err, "failed to read request body: %v", err) + assert.EqualValues(t, compressedGzipBody.Bytes(), body) + })) + defer server.Close() + + req, err := http.NewRequest("GET", server.URL, nil) + require.NoError(t, err, "failed to create request to test handler") + + client := http.Client{} + client.Transport = newCompressRoundTripper(http.DefaultTransport, configcompression.Gzip) + res, err := client.Do(req) + require.NoError(t, err) + + _, err = ioutil.ReadAll(res.Body) + require.NoError(t, err) + require.NoError(t, res.Body.Close(), "failed to close request body: %v", err) +} + +func TestHTTPContentCompressionCopyError(t *testing.T) { + testBody := bytes.NewBuffer([]byte("test")) + copyErrorCompressRoundTripper := &compressRoundTripper{ + RoundTripper: http.DefaultTransport, + compressionType: "copyFailed", + writer: func(buf *bytes.Buffer) (io.WriteCloser, error) { + return nil, fmt.Errorf("copy failed") + }, + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + })) + defer server.Close() + + req, err := http.NewRequest("GET", server.URL, testBody) + require.NoError(t, err, "failed to create request to test handler") + + client := http.Client{} + client.Transport = copyErrorCompressRoundTripper + _, err = client.Do(req) + require.Error(t, err) +} + +type closeFailBody struct { + *bytes.Buffer +} + +func (*closeFailBody) Close() error { + return fmt.Errorf("close failed") +} + +func TestHTTPContentCompressionRequestBodyCloseError(t *testing.T) { + testBody := []byte("blank") + body := &closeFailBody{ + Buffer: bytes.NewBuffer(testBody), + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + })) + defer server.Close() + + url, _ := url.Parse(server.URL) + req := &http.Request{ + Method: "GET", + URL: url, + Body: body, + } + + client := http.Client{} + client.Transport = newCompressRoundTripper(http.DefaultTransport, configcompression.Gzip) + _, err := client.Do(req) + require.Error(t, err) +} + func compressGzip(body []byte) (*bytes.Buffer, error) { var buf bytes.Buffer diff --git a/docs/release.md b/docs/release.md index 44704008cdf..016a7573355 100644 --- a/docs/release.md +++ b/docs/release.md @@ -39,17 +39,7 @@ It is possible that a core approver isn't a contrib approver. In that case, the * Update CHANGELOG.md file and rename the Unreleased section to the new release name. Add a new unreleased section at top. Use commit history feature to get the list of commits since the last release to help understand what should be in the release notes, e.g.: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.44.0...main. - * Use multimod to update the version of the collector package - * Update [versions.yaml](https://github.com/open-telemetry/opentelemetry-collector/blob/main/versions.yaml) and commit it locally - * Run `make multimod-prerelease` (it might fail if you didn't commit the change above) - - * Update the collector version in the collector builder to the new release in `./cmd/builder/internal/builder/config.go`. - - * Update the collector version in the manifest used by `make run` to the new release in `./cmd/otelcorecol/builder-config.yaml` and run `make genotelcorecol`. - - * Update the collector version in the `examples/k8s/otel-config.yaml` - - * Submit a PR with the changes and get the PR approved and merged. + * Run `make prepare-release PREVIOUS_VERSION=0.52.0 RELEASE_CANDIDATE=0.53.0` * Ensure the `main` branch builds successfully. diff --git a/exporter/loggingexporter/factory.go b/exporter/loggingexporter/factory.go index 4dc64da9d68..dca2659ebf9 100644 --- a/exporter/loggingexporter/factory.go +++ b/exporter/loggingexporter/factory.go @@ -16,6 +16,7 @@ package loggingexporter // import "go.opentelemetry.io/collector/exporter/loggin import ( "context" + "time" "go.uber.org/zap" "go.uber.org/zap/zapcore" @@ -53,50 +54,29 @@ func createDefaultConfig() config.Exporter { func createTracesExporter(_ context.Context, set component.ExporterCreateSettings, config config.Exporter) (component.TracesExporter, error) { cfg := config.(*Config) - - exporterLogger, err := createLogger(cfg) - if err != nil { - return nil, err - } - + exporterLogger := createLogger(cfg, set.TelemetrySettings.Logger) return newTracesExporter(cfg, exporterLogger, set) } func createMetricsExporter(_ context.Context, set component.ExporterCreateSettings, config config.Exporter) (component.MetricsExporter, error) { cfg := config.(*Config) - - exporterLogger, err := createLogger(cfg) - if err != nil { - return nil, err - } - + exporterLogger := createLogger(cfg, set.TelemetrySettings.Logger) return newMetricsExporter(cfg, exporterLogger, set) } func createLogsExporter(_ context.Context, set component.ExporterCreateSettings, config config.Exporter) (component.LogsExporter, error) { cfg := config.(*Config) - - exporterLogger, err := createLogger(cfg) - if err != nil { - return nil, err - } - + exporterLogger := createLogger(cfg, set.TelemetrySettings.Logger) return newLogsExporter(cfg, exporterLogger, set) } -func createLogger(cfg *Config) (*zap.Logger, error) { - // We take development config as the base since it matches the purpose - // of logging exporter being used for debugging reasons (so e.g. console encoder) - conf := zap.NewDevelopmentConfig() - conf.Level = zap.NewAtomicLevelAt(cfg.LogLevel) - conf.Sampling = &zap.SamplingConfig{ - Initial: cfg.SamplingInitial, - Thereafter: cfg.SamplingThereafter, - } +func createLogger(cfg *Config, logger *zap.Logger) *zap.Logger { + core := zapcore.NewSamplerWithOptions( + logger.Core(), + 1*time.Second, + cfg.SamplingInitial, + cfg.SamplingThereafter, + ) - logginglogger, err := conf.Build() - if err != nil { - return nil, err - } - return logginglogger, nil + return zap.New(core) } diff --git a/pdata/pcommon/alias.go b/pdata/pcommon/alias.go index f7bfd6ebbfd..c3d9a84e0b9 100644 --- a/pdata/pcommon/alias.go +++ b/pdata/pcommon/alias.go @@ -93,3 +93,6 @@ var ( // NewMapFromRaw creates a Map with values from the given map[string]interface{}. NewMapFromRaw = internal.NewMapFromRaw ) + +// NewSliceFromRaw creates a Slice with values from the given []interface{}. +var NewSliceFromRaw = internal.NewSliceFromRaw