feat: sentry integration
Cadoles/bouncer/pipeline/head This commit looks good Details

ref #3
This commit is contained in:
wpetit 2023-07-05 12:05:30 -06:00
parent a176b754cd
commit aab5452fa2
17 changed files with 291 additions and 48 deletions

11
go.mod
View File

@ -6,7 +6,7 @@ require (
forge.cadoles.com/Cadoles/go-proxy v0.0.0-20230701194111-c6b3d482cca6 forge.cadoles.com/Cadoles/go-proxy v0.0.0-20230701194111-c6b3d482cca6
github.com/Masterminds/sprig/v3 v3.2.3 github.com/Masterminds/sprig/v3 v3.2.3
github.com/btcsuite/btcd/btcutil v1.1.3 github.com/btcsuite/btcd/btcutil v1.1.3
github.com/davecgh/go-spew v1.1.1 github.com/getsentry/sentry-go v0.22.0
github.com/go-chi/chi/v5 v5.0.8 github.com/go-chi/chi/v5 v5.0.8
github.com/jedib0t/go-pretty/v6 v6.4.6 github.com/jedib0t/go-pretty/v6 v6.4.6
github.com/mitchellh/mapstructure v1.4.1 github.com/mitchellh/mapstructure v1.4.1
@ -53,11 +53,12 @@ require (
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cast v1.3.1 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 // indirect google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 // indirect
google.golang.org/protobuf v1.30.0 // indirect google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
@ -71,12 +72,12 @@ require (
github.com/dlclark/regexp2 v1.9.0 // indirect github.com/dlclark/regexp2 v1.9.0 // indirect
github.com/fatih/color v1.15.0 // indirect github.com/fatih/color v1.15.0 // indirect
github.com/go-chi/cors v1.2.1 github.com/go-chi/cors v1.2.1
github.com/go-playground/locales v0.12.1 // indirect github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.16.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/leodido/go-urn v1.1.0 // indirect github.com/leodido/go-urn v1.2.1 // indirect
github.com/lestrrat-go/blackmagic v1.0.1 // indirect github.com/lestrrat-go/blackmagic v1.0.1 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect github.com/lestrrat-go/httprc v1.0.4 // indirect

18
go.sum
View File

@ -178,19 +178,24 @@ github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBD
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/getsentry/sentry-go v0.22.0 h1:XNX9zKbv7baSEI65l+H1GEJgSeIC1c7EN5kluWaP6dM=
github.com/getsentry/sentry-go v0.22.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
@ -314,8 +319,9 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80= github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=
github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
@ -382,6 +388,7 @@ github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuh
github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4=
github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -419,8 +426,9 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@ -667,6 +675,7 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -695,6 +704,7 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View File

@ -1,11 +1,14 @@
package admin package admin
import ( import (
"context"
"fmt" "fmt"
"net/http" "net/http"
"forge.cadoles.com/cadoles/bouncer/internal/schema" "forge.cadoles.com/cadoles/bouncer/internal/schema"
"github.com/getsentry/sentry-go"
"gitlab.com/wpetit/goweb/api" "gitlab.com/wpetit/goweb/api"
"gitlab.com/wpetit/goweb/logger"
) )
const ErrCodeAlreadyExist api.ErrorCode = "already-exist" const ErrCodeAlreadyExist api.ErrorCode = "already-exist"
@ -29,3 +32,8 @@ func invalidDataErrorResponse(w http.ResponseWriter, r *http.Request, err *schem
return return
} }
func logAndCaptureError(ctx context.Context, message string, err error) {
sentry.CaptureException(err)
logger.Error(ctx, message, logger.E(err))
}

View File

@ -1,6 +1,7 @@
package admin package admin
import ( import (
"fmt"
"net/http" "net/http"
"sort" "sort"
@ -10,7 +11,6 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/wpetit/goweb/api" "gitlab.com/wpetit/goweb/api"
"gitlab.com/wpetit/goweb/logger"
) )
type QueryLayerResponse struct { type QueryLayerResponse struct {
@ -38,7 +38,7 @@ func (s *Server) queryLayer(w http.ResponseWriter, r *http.Request) {
options..., options...,
) )
if err != nil { if err != nil {
logger.Error(ctx, "could not list layers", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not list layers", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -85,7 +85,7 @@ func (s *Server) getLayer(w http.ResponseWriter, r *http.Request) {
return return
} }
logger.Error(ctx, "could not get layer", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not get layer", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -120,7 +120,7 @@ func (s *Server) deleteLayer(w http.ResponseWriter, r *http.Request) {
return return
} }
logger.Error(ctx, "could not delete layer", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not delete layer", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -156,7 +156,7 @@ func (s *Server) createLayer(w http.ResponseWriter, r *http.Request) {
layerName, err := store.ValidateName(createLayerReq.Name) layerName, err := store.ValidateName(createLayerReq.Name)
if err != nil { if err != nil {
logger.Error(r.Context(), "invalid 'name' parameter", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "invalid 'name' parameter", errors.WithStack(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeInvalidRequest, nil) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeInvalidRequest, nil)
return return
@ -165,7 +165,7 @@ func (s *Server) createLayer(w http.ResponseWriter, r *http.Request) {
layerType := store.LayerType(createLayerReq.Type) layerType := store.LayerType(createLayerReq.Type)
if !setup.LayerTypeExists(layerType) { if !setup.LayerTypeExists(layerType) {
logger.Error(r.Context(), "unknown layer type", logger.E(errors.WithStack(err)), logger.F("layerType", layerType)) logAndCaptureError(ctx, fmt.Sprintf("unknown layer type '%s'", layerType), errors.WithStack(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeInvalidRequest, nil) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeInvalidRequest, nil)
return return
@ -179,7 +179,7 @@ func (s *Server) createLayer(w http.ResponseWriter, r *http.Request) {
return return
} }
logger.Error(ctx, "could not create layer", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not create layer", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -223,7 +223,7 @@ func (s *Server) updateLayer(w http.ResponseWriter, r *http.Request) {
return return
} }
logger.Error(ctx, "could not get layer", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not get layer", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -247,7 +247,7 @@ func (s *Server) updateLayer(w http.ResponseWriter, r *http.Request) {
if updateLayerReq.Options != nil { if updateLayerReq.Options != nil {
layerOptionsSchema, err := setup.GetLayerOptionsSchema(layer.Type) layerOptionsSchema, err := setup.GetLayerOptionsSchema(layer.Type)
if err != nil { if err != nil {
logger.Error(r.Context(), "could not retrieve layer options schema", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not retrieve layer options schema", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -258,7 +258,7 @@ func (s *Server) updateLayer(w http.ResponseWriter, r *http.Request) {
}(updateLayerReq.Options) }(updateLayerReq.Options)
if err := schema.Validate(ctx, layerOptionsSchema, rawOptions); err != nil { if err := schema.Validate(ctx, layerOptionsSchema, rawOptions); err != nil {
logger.Error(r.Context(), "could not validate layer options", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not validate layer options", errors.WithStack(err))
var invalidDataErr *schema.InvalidDataError var invalidDataErr *schema.InvalidDataError
if errors.As(err, &invalidDataErr) { if errors.As(err, &invalidDataErr) {
@ -286,7 +286,7 @@ func (s *Server) updateLayer(w http.ResponseWriter, r *http.Request) {
return return
} }
logger.Error(ctx, "could not update layer", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not update layer", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -300,21 +300,7 @@ func getLayerName(w http.ResponseWriter, r *http.Request) (store.LayerName, bool
name, err := store.ValidateName(rawLayerName) name, err := store.ValidateName(rawLayerName)
if err != nil { if err != nil {
logger.Error(r.Context(), "could not parse layer name", logger.E(errors.WithStack(err))) logAndCaptureError(r.Context(), "could not parse layer name", errors.WithStack(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return "", false
}
return store.LayerName(name), true
}
func geLayerName(w http.ResponseWriter, r *http.Request) (store.LayerName, bool) {
rawLayerName := chi.URLParam(r, "layerName")
name, err := store.ValidateName(rawLayerName)
if err != nil {
logger.Error(r.Context(), "could not parse layer name", logger.E(errors.WithStack(err)))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return "", false return "", false

View File

@ -11,7 +11,6 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/wpetit/goweb/api" "gitlab.com/wpetit/goweb/api"
"gitlab.com/wpetit/goweb/logger"
) )
type QueryProxyResponse struct { type QueryProxyResponse struct {
@ -37,7 +36,7 @@ func (s *Server) queryProxy(w http.ResponseWriter, r *http.Request) {
options..., options...,
) )
if err != nil { if err != nil {
logger.Error(ctx, "could not list proxies", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not list proxies", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -79,7 +78,7 @@ func (s *Server) getProxy(w http.ResponseWriter, r *http.Request) {
return return
} }
logger.Error(ctx, "could not get proxy", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not get proxy", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -109,7 +108,7 @@ func (s *Server) deleteProxy(w http.ResponseWriter, r *http.Request) {
return return
} }
logger.Error(ctx, "could not delete proxy", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not delete proxy", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -140,14 +139,14 @@ func (s *Server) createProxy(w http.ResponseWriter, r *http.Request) {
name, err := store.ValidateName(createProxyReq.Name) name, err := store.ValidateName(createProxyReq.Name)
if err != nil { if err != nil {
logger.Error(r.Context(), "could not parse 'name' parameter", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not parse 'name' parameter", errors.WithStack(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return return
} }
if _, err := url.Parse(createProxyReq.To); err != nil { if _, err := url.Parse(createProxyReq.To); err != nil {
logger.Error(r.Context(), "could not parse 'to' parameter", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not parse 'to' parameter", errors.WithStack(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return return
@ -161,7 +160,7 @@ func (s *Server) createProxy(w http.ResponseWriter, r *http.Request) {
return return
} }
logger.Error(ctx, "could not create proxy", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not create proxy", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -207,7 +206,7 @@ func (s *Server) updateProxy(w http.ResponseWriter, r *http.Request) {
if updateProxyReq.To != nil { if updateProxyReq.To != nil {
_, err := url.Parse(*updateProxyReq.To) _, err := url.Parse(*updateProxyReq.To)
if err != nil { if err != nil {
logger.Error(r.Context(), "could not parse 'to' parameter", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not parse 'to' parameter", errors.WithStack(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return return
@ -235,7 +234,7 @@ func (s *Server) updateProxy(w http.ResponseWriter, r *http.Request) {
return return
} }
logger.Error(ctx, "could not update proxy", logger.E(errors.WithStack(err))) logAndCaptureError(ctx, "could not update proxy", errors.WithStack(err))
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
return return
@ -249,7 +248,7 @@ func getProxyName(w http.ResponseWriter, r *http.Request) (store.ProxyName, bool
name, err := store.ValidateName(rawProxyName) name, err := store.ValidateName(rawProxyName)
if err != nil { if err != nil {
logger.Error(r.Context(), "could not parse proxy name", logger.E(errors.WithStack(err))) logAndCaptureError(r.Context(), "could not parse proxy name", errors.WithStack(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return "", false return "", false
@ -263,7 +262,7 @@ func getIntQueryParam(w http.ResponseWriter, r *http.Request, param string, defa
if rawValue != "" { if rawValue != "" {
value, err := strconv.ParseInt(rawValue, 10, 64) value, err := strconv.ParseInt(rawValue, 10, 64)
if err != nil { if err != nil {
logger.Error(r.Context(), "could not parse int param", logger.F("param", param), logger.E(errors.WithStack(err))) logAndCaptureError(r.Context(), "could not parse int param", errors.WithStack(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return 0, false return 0, false
@ -296,7 +295,7 @@ func getStringableSliceValues[T ~string](w http.ResponseWriter, r *http.Request,
for _, rv := range rawValues { for _, rv := range rawValues {
v, err := validate(rv) v, err := validate(rv)
if err != nil { if err != nil {
logger.Error(r.Context(), "could not parse ids slice param", logger.F("param", param), logger.E(errors.WithStack(err))) logAndCaptureError(r.Context(), "could not parse ids slice param", errors.WithStack(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return nil, false return nil, false

View File

@ -12,6 +12,7 @@ import (
"forge.cadoles.com/cadoles/bouncer/internal/config" "forge.cadoles.com/cadoles/bouncer/internal/config"
"forge.cadoles.com/cadoles/bouncer/internal/jwk" "forge.cadoles.com/cadoles/bouncer/internal/jwk"
"forge.cadoles.com/cadoles/bouncer/internal/store" "forge.cadoles.com/cadoles/bouncer/internal/store"
sentryhttp "github.com/getsentry/sentry-go/http"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware" "github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors" "github.com/go-chi/cors"
@ -92,6 +93,16 @@ func (s *Server) run(parentCtx context.Context, addrs chan net.Addr, errs chan e
router.Use(middleware.Logger) router.Use(middleware.Logger)
if s.serverConfig.Sentry.DSN != "" {
logger.Info(ctx, "enabling sentry http middleware")
sentryMiddleware := sentryhttp.New(sentryhttp.Options{
Repanic: true,
})
router.Use(sentryMiddleware.Handle)
}
corsMiddleware := cors.New(cors.Options{ corsMiddleware := cors.New(cors.Options{
AllowedOrigins: s.serverConfig.CORS.AllowedOrigins, AllowedOrigins: s.serverConfig.CORS.AllowedOrigins,
AllowedMethods: s.serverConfig.CORS.AllowedMethods, AllowedMethods: s.serverConfig.CORS.AllowedMethods,

View File

@ -7,6 +7,7 @@ import (
"sort" "sort"
"time" "time"
"github.com/getsentry/sentry-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -90,6 +91,8 @@ func Main(buildDate, projectVersion, gitRef, defaultConfigPath string, commands
return return
} }
sentry.CaptureException(err)
debug := ctx.Bool("debug") debug := ctx.Bool("debug")
if !debug { if !debug {

View File

@ -6,6 +6,7 @@ import (
"forge.cadoles.com/cadoles/bouncer/internal/admin" "forge.cadoles.com/cadoles/bouncer/internal/admin"
"forge.cadoles.com/cadoles/bouncer/internal/command/common" "forge.cadoles.com/cadoles/bouncer/internal/command/common"
"forge.cadoles.com/cadoles/bouncer/internal/setup"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"gitlab.com/wpetit/goweb/logger" "gitlab.com/wpetit/goweb/logger"
@ -27,6 +28,14 @@ func RunCommand() *cli.Command {
logger.SetFormat(logger.Format(conf.Logger.Format)) logger.SetFormat(logger.Format(conf.Logger.Format))
logger.SetLevel(logger.Level(conf.Logger.Level)) logger.SetLevel(logger.Level(conf.Logger.Level))
projectVersion := ctx.String("projectVersion")
flushSentry, err := setup.SetupSentry(ctx.Context, conf.Admin.Sentry, projectVersion)
if err != nil {
return errors.Wrap(err, "could not initialize sentry client")
}
defer flushSentry()
srv := admin.NewServer( srv := admin.NewServer(
admin.WithServerConfig(conf.Admin), admin.WithServerConfig(conf.Admin),
admin.WithRedisConfig(conf.Redis), admin.WithRedisConfig(conf.Redis),

View File

@ -28,6 +28,14 @@ func RunCommand() *cli.Command {
logger.SetFormat(logger.Format(conf.Logger.Format)) logger.SetFormat(logger.Format(conf.Logger.Format))
logger.SetLevel(logger.Level(conf.Logger.Level)) logger.SetLevel(logger.Level(conf.Logger.Level))
projectVersion := ctx.String("projectVersion")
flushSentry, err := setup.SetupSentry(ctx.Context, conf.Proxy.Sentry, projectVersion)
if err != nil {
return errors.Wrap(err, "could not initialize sentry client")
}
defer flushSentry()
layers, err := setup.GetLayers(ctx.Context, conf) layers, err := setup.GetLayers(ctx.Context, conf)
if err != nil { if err != nil {
return errors.Wrap(err, "could not initialize director layers") return errors.Wrap(err, "could not initialize director layers")

View File

@ -5,6 +5,7 @@ type AdminServerConfig struct {
CORS CORSConfig `yaml:"cors"` CORS CORSConfig `yaml:"cors"`
Auth AuthConfig `yaml:"auth"` Auth AuthConfig `yaml:"auth"`
Metrics MetricsConfig `yaml:"metrics"` Metrics MetricsConfig `yaml:"metrics"`
Sentry SentryConfig `yaml:"sentry"`
} }
func NewDefaultAdminServerConfig() AdminServerConfig { func NewDefaultAdminServerConfig() AdminServerConfig {
@ -13,6 +14,7 @@ func NewDefaultAdminServerConfig() AdminServerConfig {
CORS: NewDefaultCORSConfig(), CORS: NewDefaultCORSConfig(),
Auth: NewDefaultAuthConfig(), Auth: NewDefaultAuthConfig(),
Metrics: NewDefaultMetricsConfig(), Metrics: NewDefaultMetricsConfig(),
Sentry: NewDefaultSentryConfig(),
} }
} }

View File

@ -53,6 +53,29 @@ func (ii *InterpolatedInt) UnmarshalYAML(value *yaml.Node) error {
return nil return nil
} }
type InterpolatedFloat float64
func (ifl *InterpolatedFloat) UnmarshalYAML(value *yaml.Node) error {
var str string
if err := value.Decode(&str); err != nil {
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
}
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
str = os.Getenv(match[1])
}
floatVal, err := strconv.ParseFloat(str, 10)
if err != nil {
return errors.Wrapf(err, "could not parse float '%v', line '%d'", str, value.Line)
}
*ifl = InterpolatedFloat(floatVal)
return nil
}
type InterpolatedBool bool type InterpolatedBool bool
func (ib *InterpolatedBool) UnmarshalYAML(value *yaml.Node) error { func (ib *InterpolatedBool) UnmarshalYAML(value *yaml.Node) error {

View File

@ -7,6 +7,7 @@ type ProxyServerConfig struct {
Metrics MetricsConfig `yaml:"metrics"` Metrics MetricsConfig `yaml:"metrics"`
Transport TransportConfig `yaml:"transport"` Transport TransportConfig `yaml:"transport"`
Dial DialConfig `yaml:"dial"` Dial DialConfig `yaml:"dial"`
Sentry SentryConfig `yaml:"sentry"`
} }
// See https://pkg.go.dev/net/http#Transport // See https://pkg.go.dev/net/http#Transport
@ -32,6 +33,7 @@ func NewDefaultProxyServerConfig() ProxyServerConfig {
Metrics: NewDefaultMetricsConfig(), Metrics: NewDefaultMetricsConfig(),
Transport: NewDefaultTransportConfig(), Transport: NewDefaultTransportConfig(),
Dial: NewDefaultDialConfig(), Dial: NewDefaultDialConfig(),
Sentry: NewDefaultSentryConfig(),
} }
} }

43
internal/config/sentry.go Normal file
View File

@ -0,0 +1,43 @@
package config
import "time"
// Sentry configuration
// See https://pkg.go.dev/github.com/getsentry/sentry-go?utm_source=godoc#ClientOptions
type SentryConfig struct {
DSN InterpolatedString `yaml:"dsn"`
Debug InterpolatedBool `yaml:"debug"`
FlushTimeout *InterpolatedDuration `yaml:"flushTimeout"`
AttachStacktrace InterpolatedBool `yaml:"attachStacktrace"`
SampleRate InterpolatedFloat `yaml:"sampleRate"`
EnableTracing InterpolatedBool `yaml:"enableTracing"`
TracesSampleRate InterpolatedFloat `yaml:"tracesSampleRate"`
ProfilesSampleRate InterpolatedFloat `yaml:"profilesSampleRate"`
IgnoreErrors InterpolatedStringSlice `yaml:"ignoreErrors"`
SendDefaultPII InterpolatedBool `yaml:"sendDefaultPII"`
ServerName InterpolatedString `yaml:"serverName"`
Environment InterpolatedString `yaml:"environment"`
MaxBreadcrumbs InterpolatedInt `yaml:"maxBreadcrumbs"`
MaxSpans InterpolatedInt `yaml:"maxSpans"`
MaxErrorDepth InterpolatedInt `yaml:"maxErrorDepth"`
}
func NewDefaultSentryConfig() SentryConfig {
return SentryConfig{
DSN: "",
Debug: false,
FlushTimeout: NewInterpolatedDuration(2 * time.Second),
AttachStacktrace: true,
SampleRate: 1,
EnableTracing: true,
TracesSampleRate: 0.2,
ProfilesSampleRate: 1,
IgnoreErrors: []string{},
SendDefaultPII: false,
ServerName: "",
Environment: "",
MaxBreadcrumbs: 0,
MaxSpans: 1000,
MaxErrorDepth: 10,
}
}

43
internal/logger/writer.go Normal file
View File

@ -0,0 +1,43 @@
package logger
import (
"context"
"io"
"gitlab.com/wpetit/goweb/logger"
)
type Writer struct {
ctx context.Context
level logger.Level
}
// Write implements io.Writer.
func (w *Writer) Write(p []byte) (n int, err error) {
w.log(string(p))
return len(p), nil
}
func (w *Writer) log(message string) {
switch w.level {
case logger.LevelDebug:
logger.Debug(w.ctx, message)
case logger.LevelInfo:
logger.Info(w.ctx, message)
case logger.LevelWarn:
logger.Warn(w.ctx, message)
case logger.LevelError:
logger.Error(w.ctx, message)
case logger.LevelCritical:
logger.Critical(w.ctx, message)
default:
logger.Debug(w.ctx, message)
}
}
func NewWriter(ctx context.Context, level logger.Level) *Writer {
return &Writer{ctx, level}
}
var _ io.Writer = &Writer{}

View File

@ -15,6 +15,8 @@ import (
"forge.cadoles.com/cadoles/bouncer/internal/config" "forge.cadoles.com/cadoles/bouncer/internal/config"
"forge.cadoles.com/cadoles/bouncer/internal/proxy/director" "forge.cadoles.com/cadoles/bouncer/internal/proxy/director"
"forge.cadoles.com/cadoles/bouncer/internal/store" "forge.cadoles.com/cadoles/bouncer/internal/store"
"github.com/getsentry/sentry-go"
sentryhttp "github.com/getsentry/sentry-go/http"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware" "github.com/go-chi/chi/v5/middleware"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -89,6 +91,16 @@ func (s *Server) run(parentCtx context.Context, addrs chan net.Addr, errs chan e
router.Use(middleware.RequestLogger(bouncerChi.NewLogFormatter())) router.Use(middleware.RequestLogger(bouncerChi.NewLogFormatter()))
if s.serverConfig.Sentry.DSN != "" {
logger.Info(ctx, "enabling sentry http middleware")
sentryMiddleware := sentryhttp.New(sentryhttp.Options{
Repanic: true,
})
router.Use(sentryMiddleware.Handle)
}
if s.serverConfig.Metrics.Enabled { if s.serverConfig.Metrics.Enabled {
metrics := s.serverConfig.Metrics metrics := s.serverConfig.Metrics
@ -169,7 +181,10 @@ func (s *Server) createReverseProxy(ctx context.Context, target *url.URL) *httpu
} }
func (s *Server) errorHandler(w http.ResponseWriter, r *http.Request, err error) { func (s *Server) errorHandler(w http.ResponseWriter, r *http.Request, err error) {
logger.Error(r.Context(), "proxy error", logger.E(errors.WithStack(err))) err = errors.WithStack(err)
logger.Error(r.Context(), "proxy error", logger.E(err))
sentry.CaptureException(err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
} }

42
internal/setup/sentry.go Normal file
View File

@ -0,0 +1,42 @@
package setup
import (
"context"
"time"
"forge.cadoles.com/cadoles/bouncer/internal/config"
loggerWriter "forge.cadoles.com/cadoles/bouncer/internal/logger"
"github.com/getsentry/sentry-go"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
func SetupSentry(ctx context.Context, conf config.SentryConfig, release string) (func(), error) {
err := sentry.Init(sentry.ClientOptions{
Dsn: string(conf.DSN),
Debug: bool(conf.Debug),
AttachStacktrace: bool(conf.AttachStacktrace),
SampleRate: float64(conf.SampleRate),
EnableTracing: bool(conf.EnableTracing),
TracesSampleRate: float64(conf.TracesSampleRate),
ProfilesSampleRate: float64(conf.ProfilesSampleRate),
IgnoreErrors: conf.IgnoreErrors,
SendDefaultPII: bool(conf.SendDefaultPII),
ServerName: string(conf.ServerName),
Release: release,
Environment: string(conf.Environment),
MaxBreadcrumbs: int(conf.MaxBreadcrumbs),
MaxSpans: int(conf.MaxSpans),
MaxErrorDepth: int(conf.MaxErrorDepth),
DebugWriter: loggerWriter.NewWriter(ctx, logger.LevelDebug),
})
if err != nil {
return nil, errors.WithStack(err)
}
flush := func() {
sentry.Flush(time.Duration(*conf.FlushTimeout))
}
return flush, nil
}

View File

@ -46,6 +46,25 @@ admin:
# Mettre à null pour désactiver l'authentification # Mettre à null pour désactiver l'authentification
basicAuth: null basicAuth: null
# Configuration de l'intégration Sentry
# Voir https://pkg.go.dev/github.com/getsentry/sentry-go?utm_source=godoc#ClientOptions
sentry:
dsn: ""
debug: false
flushTimeout: 2s
attachStacktrace: true
sampleRate: 1
enableTracing: true
tracesSampleRate: 0.2
profilesSampleRate: 1
ignoreErrors: []
sendDefaultPII: false
serverName: ""
environment: ""
maxBreadcrumbs: 0
maxSpans: 1000
maxErrorDepth: 10
# Configuration du service "proxy" # Configuration du service "proxy"
proxy: proxy:
http: http:
@ -85,6 +104,25 @@ proxy:
readBufferSize: 4096 readBufferSize: 4096
maxResponseHeaderBytes: 0 maxResponseHeaderBytes: 0
# Configuration de l'intégration Sentry
# Voir https://pkg.go.dev/github.com/getsentry/sentry-go?utm_source=godoc#ClientOptions
sentry:
dsn: ""
debug: false
flushTimeout: 2s
attachStacktrace: true
sampleRate: 1
enableTracing: true
tracesSampleRate: 0.2
profilesSampleRate: 1
ignoreErrors: []
sendDefaultPII: false
serverName: ""
environment: ""
maxBreadcrumbs: 0
maxSpans: 1000
maxErrorDepth: 10
# Configuration des connexions TCP # Configuration des connexions TCP
# Voir https://pkg.go.dev/net#Dialer # Voir https://pkg.go.dev/net#Dialer
dial: dial: