GitHub

@@ -0,0 +1,127 @@

1+

// Copyright 2022 The Parca Authors

2+

// Licensed under the Apache License, Version 2.0 (the "License");

3+

// you may not use this file except in compliance with the License.

4+

// You may obtain a copy of the License at

5+

//

6+

// http://www.apache.org/licenses/LICENSE-2.0

7+

//

8+

// Unless required by applicable law or agreed to in writing, software

9+

// distributed under the License is distributed on an "AS IS" BASIS,

10+

// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

11+

// See the License for the specific language governing permissions and

12+

// limitations under the License.

13+14+

package debuginfo

15+16+

import (

17+

"fmt"

18+

"io"

19+

"net/http"

20+

"net/url"

21+

"path"

22+

"time"

23+24+

"github.com/go-kit/log"

25+

"github.com/go-kit/log/level"

26+

"github.com/thanos-io/thanos/pkg/objstore"

27+

"github.com/thanos-io/thanos/pkg/objstore/client"

28+

"golang.org/x/net/context"

29+

"gopkg.in/yaml.v2"

30+

)

31+32+

type DebugInfodClient interface {

33+

GetDebugInfo(ctx context.Context, buildid string) (io.ReadCloser, error)

34+

}

35+36+

type HTTPDebugInfodClient struct {

37+

logger log.Logger

38+

UpstreamServer *url.URL

39+

timeoutDuration time.Duration

40+

}

41+42+

type DebugInfodClientObjectStorageCache struct {

43+

logger log.Logger

44+

client DebugInfodClient

45+

bucket objstore.Bucket

46+

}

47+48+

func NewHTTPDebugInfodClient(logger log.Logger, serverURL string, timeoutDuration time.Duration) (*HTTPDebugInfodClient, error) {

49+

parsedURL, err := url.Parse(serverURL)

50+

if err != nil {

51+

return nil, err

52+

}

53+

return &HTTPDebugInfodClient{

54+

logger: logger,

55+

UpstreamServer: parsedURL,

56+

timeoutDuration: timeoutDuration,

57+

}, nil

58+

}

59+60+

func NewDebugInfodClientWithObjectStorageCache(logger log.Logger, config *Config, h DebugInfodClient) (*DebugInfodClientObjectStorageCache, error) {

61+

cfg, err := yaml.Marshal(config.Bucket)

62+

if err != nil {

63+

return nil, fmt.Errorf("marshal content of debuginfod object storage configuration: %w", err)

64+

}

65+66+

bucket, err := client.NewBucket(logger, cfg, nil, "parca")

67+

if err != nil {

68+

return nil, fmt.Errorf("instantiate debuginfod object storage: %w", err)

69+

}

70+

return &DebugInfodClientObjectStorageCache{

71+

logger: logger,

72+

client: h,

73+

bucket: bucket,

74+

}, nil

75+

}

76+77+

func (c *DebugInfodClientObjectStorageCache) GetDebugInfo(ctx context.Context, buildID string) (io.ReadCloser, error) {

78+

path := "/debuginfod-cache/" + buildID + "/debuginfo"

79+80+

if exists, _ := c.bucket.Exists(ctx, path); exists {

81+

debuginfoFile, err := c.bucket.Get(ctx, path)

82+

if err != nil {

83+

return nil, fmt.Errorf("failed to download object file from debuginfod cache: build_id: %v: %w", buildID, err)

84+

}

85+

return debuginfoFile, nil

86+

}

87+88+

debugInfo, err := c.client.GetDebugInfo(ctx, buildID)

89+

if err != nil {

90+

return nil, ErrDebugInfoNotFound

91+

}

92+93+

err = c.bucket.Upload(ctx, path, debugInfo)

94+

if err != nil {

95+

return nil, fmt.Errorf("failed to upload to debuginfod cache: %w", err)

96+

}

97+98+

debugInfoReader, err := c.bucket.Get(ctx, path)

99+

if err != nil {

100+

return nil, fmt.Errorf("failed to download object file from debuginfod cache: build_id: %v: %w", buildID, err)

101+

}

102+103+

return debugInfoReader, nil

104+

}

105+106+

func (c *HTTPDebugInfodClient) GetDebugInfo(ctx context.Context, buildID string) (io.ReadCloser, error) {

107+

buildIDURL := *c.UpstreamServer

108+

buildIDURL.Path = path.Join(buildIDURL.Path, buildID, "debuginfo")

109+110+

ctx, cancel := context.WithTimeout(ctx, c.timeoutDuration)

111+

defer cancel()

112+113+

req, err := http.NewRequestWithContext(ctx, "GET", buildIDURL.String(), nil)

114+

if err != nil {

115+

level.Debug(c.logger).Log("msg", "failed to create new HTTP request", "err", err)

116+

return nil, err

117+

}

118+119+

client := http.DefaultClient

120+

resp, err := client.Do(req)

121+

if err != nil {

122+

level.Debug(c.logger).Log("msg", "object not found in public server", "object", buildID, "err", err)

123+

return nil, ErrDebugInfoNotFound

124+

}

125+126+

return resp.Body, nil

127+

}

Read the original on github.com ↗