Repository: tetratelabs/getenvoy
Pull request #212 (2021-05-12 02:43:28)

Refactors logging to not bother users on expected errors
Before, we had debug logs that were not possible to enable, as well logs
that bothered users with situations they could not action (such as vague
details about child process signals.). This stops logging on aspects the
user cannot control. It tightens logging so that if there's something we
don't expect, the user will see it.

For example, we know certain OS utilities are unimplemented, so we skip
writing files or fields when that happens. However, we don't bother
users. If there is something unexpected, it is logged at most once per
debug utility. We do not log anything anymore about a possibility of
someone doing "kill -9" and leaving the child envoy around. This is pure
distraction for most people.

Signed-off-by: Adrian Cole <adrian@tetrate.io>

codefromthecrypt: Merging this increases statement coverage from 82.3% to 84.2%
codefromthecrypt: @mathetake I noticed we only used tetrate logging in a couple places after this, so went ahead and used standard logging for the same. deps are a lot clearer now.

Patch:
diff --git a/go.mod b/go.mod
index 0680e32..e177965 100644
--- a/go.mod
+++ b/go.mod
@@ -18,13 +18,11 @@ require (
 	github.com/shirou/gopsutil/v3 v3.21.4
 	github.com/spf13/cobra v1.1.3
 	github.com/stretchr/testify v1.7.0
-	github.com/tetratelabs/log v0.0.0-20210422163326-7ba70517903b
 	github.com/tklauser/go-sysconf v0.3.5 // indirect
 	github.com/ulikunitz/xz v0.5.10 // indirect
-	go.uber.org/multierr v1.7.0 // indirect
 	golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf // indirect
 	golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
 	golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect
-	google.golang.org/grpc v1.37.0 // indirect
 	google.golang.org/protobuf v1.26.0
+	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
 )
diff --git a/go.sum b/go.sum
index 0073d6b..3bc1eae 100644
--- a/go.sum
+++ b/go.sum
@@ -11,7 +11,6 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
@@ -32,10 +31,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -51,11 +48,6 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
 github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
 github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
 github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -77,13 +69,6 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
@@ -92,16 +77,12 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -187,7 +168,6 @@ github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuR
 github.com/pierrec/lz4/v4 v4.1.6 h1:ueMTcBBFrbT8K4uGDNNZPa8Z7LtPV7Cl0TDjaeHxP44=
 github.com/pierrec/lz4/v4 v4.1.6/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -196,7 +176,6 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@@ -235,14 +214,10 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
-github.com/tetratelabs/log v0.0.0-20210422163326-7ba70517903b h1:QjfIzzC2Zoe542WRrJdBymP/CrlwIXD8lYFiXNUTnpA=
-github.com/tetratelabs/log v0.0.0-20210422163326-7ba70517903b/go.mod h1:f/tP3FhNTKy6gn0QjYCXViykWjTHceFedy5O4xklKCE=
 github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
 github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4=
 github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
@@ -261,18 +236,8 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
-go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
-go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
-go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
-go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -294,7 +259,6 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@@ -366,16 +330,12 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8=
 golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
@@ -398,25 +358,9 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
 google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c=
-google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
@@ -426,12 +370,9 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
-gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
@@ -441,7 +382,5 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/pkg/binary/envoy/debug/admin.go b/pkg/binary/envoy/debug/admin.go
index c7c1966..0629983 100644
--- a/pkg/binary/envoy/debug/admin.go
+++ b/pkg/binary/envoy/debug/admin.go
@@ -36,10 +36,11 @@ var adminAPIPaths = map[string]string{
 	"runtime":           "runtime.json",
 }
 
-// EnableEnvoyAdminDataCollection is a preset option that registers collection of Envoy Admin API information
-func EnableEnvoyAdminDataCollection(r *envoy.Runtime) {
+// enableEnvoyAdminDataCollection is a preset option that registers collection of Envoy Admin API information
+func enableEnvoyAdminDataCollection(r *envoy.Runtime) error {
 	e := envoyAdminDataCollection{r.GetAdminAddress, r.GetWorkingDir()}
 	r.RegisterPreTermination(e.retrieveAdminAPIData)
+	return nil
 }
 
 type envoyAdminDataCollection struct {
diff --git a/pkg/binary/envoy/debug/all.go b/pkg/binary/envoy/debug/all.go
deleted file mode 100644
index 054ec1e..0000000
--- a/pkg/binary/envoy/debug/all.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2020 Tetrate
-//
-// 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.
-
-package debug
-
-import (
-	"github.com/tetratelabs/getenvoy/pkg/binary/envoy"
-)
-
-// EnableAll returns all debug options.
-func EnableAll(r *envoy.Runtime) {
-	EnableEnvoyAdminDataCollection(r)
-	EnableEnvoyLogCollection(r)
-	EnableNodeCollection(r)
-	EnableOpenFilesDataCollection(r)
-}
diff --git a/pkg/binary/envoy/debug/debug.go b/pkg/binary/envoy/debug/debug.go
new file mode 100644
index 0000000..b67c3fa
--- /dev/null
+++ b/pkg/binary/envoy/debug/debug.go
@@ -0,0 +1,60 @@
+// Copyright 2021 Tetrate
+//
+// 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.
+
+package debug
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/tetratelabs/getenvoy/pkg/binary/envoy"
+)
+
+// EnableAll enables all debug options invoking r.LogDebug on each that failed
+func EnableAll(r *envoy.Runtime) {
+	for _, debug := range []func(*envoy.Runtime) error{
+		enableEnvoyAdminDataCollection,
+		enableEnvoyLogCollection,
+		enableNodeCollection,
+		enableOpenFilesDataCollection,
+	} {
+		if err := debug(r); err != nil {
+			r.LogDebug("failed to enable debug option: %v", err)
+		}
+	}
+}
+
+// wrapError wraps an error from using "gopsutil" or returns nil on "not implemented yet".
+// We don't err on unimplemented because we don't want to disturb users for unresolvable reasons.
+func wrapError(ctx context.Context, err error, field string, pid int32) error {
+	if err == nil {
+		err = ctx.Err()
+	}
+	if err != nil && err.Error() != "not implemented yet" { // don't log if it will never work
+		return fmt.Errorf("unable to retrieve %s of pid %d: %w", field, pid, err)
+	}
+	return nil
+}
+
+// writeJSON centralizes logic to avoid writing empty files.
+func writeJSON(result interface{}, filename string) error {
+	sb := new(strings.Builder)
+	if err := json.NewEncoder(sb).Encode(result); err != nil {
+		return fmt.Errorf("error serializing %v as JSON: %w", sb, err)
+	}
+	return os.WriteFile(filename, []byte(sb.String()), 0600)
+}
diff --git a/pkg/binary/envoy/debug/log.go b/pkg/binary/envoy/debug/log.go
index 3690494..ea905e7 100644
--- a/pkg/binary/envoy/debug/log.go
+++ b/pkg/binary/envoy/debug/log.go
@@ -20,21 +20,19 @@ import (
 	"os"
 	"path/filepath"
 
-	"github.com/tetratelabs/log"
-
 	"github.com/tetratelabs/getenvoy/pkg/binary/envoy"
 )
 
-// EnableEnvoyLogCollection is a preset option that registers collection of Envoy access logs and stderr
-func EnableEnvoyLogCollection(r *envoy.Runtime) {
+// enableEnvoyLogCollection is a preset option that registers collection of Envoy access logs and stderr
+func enableEnvoyLogCollection(r *envoy.Runtime) error {
 	logsDir := filepath.Join(r.GetWorkingDir(), "logs")
 	if err := os.MkdirAll(logsDir, 0750); err != nil {
-		log.Errorf("unable to create directory %q, so no logs will be captured: %v", logsDir, err)
-		return
+		return fmt.Errorf("unable to create directory %q, so no logs will be captured: %w", logsDir, err)
 	}
 	e := envoyLogCollection{r, logsDir}
 	r.RegisterPreStart(e.captureStdout)
 	r.RegisterPreStart(e.captureStderr)
+	return nil
 }
 
 type envoyLogCollection struct {
@@ -76,7 +74,7 @@ func createLogFile(path string) (*os.File, error) {
 	// #nosec -> logs can be written anywhere
 	f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0600)
 	if err != nil {
-		return nil, fmt.Errorf("unable to open file to write logs to %v: %v", path, err)
+		return nil, fmt.Errorf("unable to open file to write logs to %v: %w", path, err)
 	}
 	return f, nil
 }
diff --git a/pkg/binary/envoy/debug/lsof.go b/pkg/binary/envoy/debug/lsof.go
index adae92d..8545824 100644
--- a/pkg/binary/envoy/debug/lsof.go
+++ b/pkg/binary/envoy/debug/lsof.go
@@ -16,14 +16,12 @@ package debug
 
 import (
 	"context"
-	"encoding/json"
 	"fmt"
 	"os"
 	"path/filepath"
 	"syscall"
 
 	"github.com/shirou/gopsutil/v3/process"
-	"github.com/tetratelabs/log"
 
 	"github.com/tetratelabs/getenvoy/pkg/binary/envoy"
 )
@@ -45,16 +43,16 @@ type OpenFileStat struct {
 	Name   string `json:"name"` // name of the mount point and file system on which the file resides
 }
 
-// EnableOpenFilesDataCollection is a preset option that registers collection of statistics of files opened by envoy
-// instance(s). This is unsupported on macOS/Darwin because it does not support process.OpenFiles
-func EnableOpenFilesDataCollection(r *envoy.Runtime) {
+// enableOpenFilesDataCollection is a preset option that registers collection of statistics of files opened by envoy
+// instance(s).
+func enableOpenFilesDataCollection(r *envoy.Runtime) error {
 	lsofDir := filepath.Join(r.GetWorkingDir(), "lsof")
 	if err := os.MkdirAll(lsofDir, 0750); err != nil {
-		log.Errorf("unable to create directory %q, so lsof will not be captured: %v", lsofDir, err)
-		return
+		return fmt.Errorf("unable to create directory %q, so lsof will not be captured: %w", lsofDir, err)
 	}
 	o := openFilesDataCollection{r.GetPid, lsofDir}
 	r.RegisterPreTermination(o.retrieveOpenFilesData)
+	return nil
 }
 
 type openFilesDataCollection struct {
@@ -63,15 +61,7 @@ type openFilesDataCollection struct {
 }
 
 // retrieveOpenFilesData writes statistics of open files associated with envoy instance(s) to a json file
-// Errors from platform-specific libraries log to debug instead of raising an error or logging in an error category.
-// This avoids filling logs for unresolvable reasons.
 func (o *openFilesDataCollection) retrieveOpenFilesData() error {
-	f, err := os.Create(filepath.Join(o.lsofDir, "lsof.json"))
-	if err != nil {
-		return fmt.Errorf("error in creating a file to write open file statistics to: %w", err)
-	}
-	defer f.Close() //nolint
-
 	// get pid of envoy instance
 	p, err := o.getPid()
 	if err != nil {
@@ -83,26 +73,25 @@ func (o *openFilesDataCollection) retrieveOpenFilesData() error {
 	defer cancel()
 
 	envoyProcess, err := process.NewProcessWithContext(ctx, pid)
-	if logDebugOnError(ctx, err, "process", pid) {
-		return nil
+	if w := wrapError(ctx, err, "process", pid); w != nil {
+		return w
 	}
 
 	result := make([]OpenFileStat, 0)
-	// print open file stats for all envoy instances
-	// relevant fields of the process
+	// print open file stats for all envoy relevant fields of the process
 	username, err := envoyProcess.UsernameWithContext(ctx)
-	if logDebugOnError(ctx, err, "username", pid) {
-		return nil
+	if w := wrapError(ctx, err, "username", pid); w != nil {
+		return w
 	}
 
 	name, err := envoyProcess.NameWithContext(ctx)
-	if logDebugOnError(ctx, err, "name", pid) {
-		return nil
+	if w := wrapError(ctx, err, "name", pid); w != nil {
+		return w
 	}
 
 	openFiles, err := envoyProcess.OpenFilesWithContext(ctx)
-	if logDebugOnError(ctx, err, "open files", pid) {
-		return nil
+	if w := wrapError(ctx, err, "open files", pid); w != nil {
+		return w
 	}
 
 	for _, stat := range openFiles {
@@ -126,8 +115,8 @@ func (o *openFilesDataCollection) retrieveOpenFilesData() error {
 		result = append(result, ofStat)
 	}
 
-	if err = json.NewEncoder(f).Encode(result); err != nil {
-		return fmt.Errorf("error writing JSON to file %v: %w", f, err)
+	if len(result) == 0 {
+		return nil // don't write a file on an unsupported platform
 	}
-	return nil
+	return writeJSON(result, filepath.Join(o.lsofDir, "lsof.json"))
 }
diff --git a/pkg/binary/envoy/debug/node.go b/pkg/binary/envoy/debug/node.go
index f99e7f8..10f3b9f 100644
--- a/pkg/binary/envoy/debug/node.go
+++ b/pkg/binary/envoy/debug/node.go
@@ -16,7 +16,6 @@ package debug
 
 import (
 	"context"
-	"encoding/json"
 	"fmt"
 	"io"
 	"os"
@@ -27,22 +26,21 @@ import (
 
 	"github.com/shirou/gopsutil/v3/net"
 	"github.com/shirou/gopsutil/v3/process"
-	"github.com/tetratelabs/log"
 
 	"github.com/tetratelabs/getenvoy/pkg/binary/envoy"
 )
 
-// EnableNodeCollection is a preset option that registers collection of node level information for debugging
-func EnableNodeCollection(r *envoy.Runtime) {
+// enableNodeCollection is a preset option that registers collection of node level information for debugging
+func enableNodeCollection(r *envoy.Runtime) error {
 	nodeDir := filepath.Join(r.GetWorkingDir(), "node")
 	if err := os.MkdirAll(nodeDir, 0750); err != nil {
-		log.Errorf("unable to create directory %q, so node data will not be captured: %v", nodeDir, err)
-		return
+		return fmt.Errorf("unable to create directory %q, so node data will not be captured: %w", nodeDir, err)
 	}
 	n := nodeCollection{nodeDir}
 	r.RegisterPreTermination(n.ps)
 	r.RegisterPreTermination(n.networkInterfaces)
 	r.RegisterPreTermination(n.activeConnections)
+	return nil
 }
 
 type nodeCollection struct {
@@ -52,8 +50,6 @@ type nodeCollection struct {
 // Don't wait forever. This has hung on macOS before
 const processTimeout = 3 * time.Second
 
-// Errors from platform-specific libraries log to debug instead of raising an error or logging in an error category.
-// This avoids filling logs for unresolvable reasons.
 func (n *nodeCollection) ps() error {
 	f, err := os.Create(filepath.Join(n.nodeDir, "ps.txt"))
 	if err != nil {
@@ -65,34 +61,25 @@ func (n *nodeCollection) ps() error {
 	defer cancel()
 
 	processes, err := process.ProcessesWithContext(ctx)
-	if ctx.Err() == context.DeadlineExceeded {
-		log.Debugf("timeout getting a list of running processes")
-		return nil
+	if err == nil {
+		err = ctx.Err()
 	}
 	if err != nil {
-		log.Debugf("unable to get list of running processes: %v", err)
-		return nil
+		if err.Error() == "not implemented yet" { // internal error used by gopsutil
+			return nil // It will never work, so there's no reason to bother users
+		}
+		return fmt.Errorf("unable to get list of running processes: %w", err)
 	}
 
-	return printProcessTable(ctx, f, processes)
-}
-
-func printProcessTable(ctx context.Context, out io.Writer, processes []*process.Process) error {
-	w := tabwriter.NewWriter(out, 0, 8, 5, ' ', 0)
-	fmt.Fprintln(w, "PID\tUSERNAME\tSTATUS\tRSS\tVSZ\tMINFLT\tMAJFLT\tPCPU\tPMEM\tARGS")
-	for _, p := range processes {
-		proc := safeProc(ctx, p)
-		if proc == empty { // Ignore, but continue. The process could have died between the process listing and now.
-			continue
-		}
-		status := ""
-		if len(proc.status) > 0 {
-			status = proc.status[0]
+	parsed, err := parseProcessTable(ctx, processes)
+	if len(parsed) == 0 {
+		if err != nil {
+			return fmt.Errorf("unable to parse any processes: %w", err)
 		}
-		fmt.Fprintf(w, "%v\t%v\t%v\t%v\t%v\t%v\t%v\t%.2f\t%.2f\t%v\n", proc.pid, proc.username, status, proc.rss, proc.vms, proc.minflt,
-			proc.majflt, proc.pCPU, proc.pMem, proc.cmd)
+		return nil
 	}
-	return w.Flush()
+
+	return printProcessTable(f, parsed)
 }
 
 type proc struct {
@@ -104,48 +91,64 @@ type proc struct {
 	pMem                     float32
 }
 
-var empty = &proc{}
+// parseProcessTable returns processes that could be parsed and the first error
+func parseProcessTable(ctx context.Context, processes []*process.Process) ([]*proc, error) {
+	procs := make([]*proc, 0, len(processes))
+	var err error
+	for _, p := range processes {
+		parsed, e := parseProc(ctx, p)
+		if e != nil { // Continue as the process could have died between the process listing and now.
+			if err == nil { // Capture only one error
+				err = e
+			}
+			continue
+		}
+		procs = append(procs, parsed)
+	}
+	return procs, err
+}
 
-func safeProc(ctx context.Context, p *process.Process) *proc {
+// parseProc returns a proc if there were no errors parsing its data
+func parseProc(ctx context.Context, p *process.Process) (*proc, error) {
 	user, err := p.UsernameWithContext(ctx)
-	if logDebugOnError(ctx, err, "username", p.Pid) {
-		return empty
+	if w := wrapError(ctx, err, "username", p.Pid); w != nil {
+		return nil, w
 	}
 
 	status, err := p.StatusWithContext(ctx)
-	if logDebugOnError(ctx, err, "status", p.Pid) {
-		return empty
+	if w := wrapError(ctx, err, "status", p.Pid); w != nil {
+		return nil, w
 	}
 
 	mem, err := p.MemoryInfoWithContext(ctx)
-	if logDebugOnError(ctx, err, "memory information", p.Pid) {
-		return empty
+	if w := wrapError(ctx, err, "memory information", p.Pid); w != nil {
+		return nil, w
 	}
 	if mem == nil {
 		mem = &process.MemoryInfoStat{}
 	}
 
 	pagefault, err := p.PageFaultsWithContext(ctx)
-	if logDebugOnError(ctx, err, "page faults", p.Pid) {
-		return empty
+	if w := wrapError(ctx, err, "page faults", p.Pid); w != nil {
+		return nil, w
 	}
 	if pagefault == nil {
 		pagefault = &process.PageFaultsStat{}
 	}
 
 	pCPU, err := p.CPUPercentWithContext(ctx)
-	if logDebugOnError(ctx, err, "CPU percent", p.Pid) {
-		return empty
+	if w := wrapError(ctx, err, "CPU percent", p.Pid); w != nil {
+		return nil, w
 	}
 
 	pMem, err := p.MemoryPercentWithContext(ctx)
-	if logDebugOnError(ctx, err, "memory percent", p.Pid) {
-		return empty
+	if w := wrapError(ctx, err, "memory percent", p.Pid); w != nil {
+		return nil, w
 	}
 
 	cmd, err := p.CmdlineWithContext(ctx)
-	if logDebugOnError(ctx, err, "command-line", p.Pid) {
-		return empty
+	if w := wrapError(ctx, err, "command-line", p.Pid); w != nil {
+		return nil, w
 	}
 
 	return &proc{
@@ -158,38 +161,39 @@ func safeProc(ctx context.Context, p *process.Process) *proc {
 		pCPU:     pCPU,
 		pMem:     pMem,
 		cmd:      cmd,
-	}
+	}, nil
 }
 
-func logDebugOnError(ctx context.Context, err error, field string, pid int32) bool {
-	if ctx.Err() == context.DeadlineExceeded {
-		log.Debugf("timeout getting %s of pid %d", field, pid)
-		return true
-	} else if err != nil {
-		log.Debugf("unable to retrieve %s of pid %d: %v", field, pid, err)
-		return true
+func printProcessTable(out io.Writer, parsed []*proc) error {
+	// Now, start writing the process table
+	w := tabwriter.NewWriter(out, 0, 8, 5, ' ', 0)
+	if _, err := fmt.Fprintln(w, "PID\tUSERNAME\tSTATUS\tRSS\tVSZ\tMINFLT\tMAJFLT\tPCPU\tPMEM\tARGS"); err != nil {
+		return err
 	}
-	return false
+
+	for _, p := range parsed {
+		status := ""
+		if len(p.status) > 0 {
+			status = p.status[0]
+		}
+		if _, err := fmt.Fprintf(w, "%v\t%v\t%v\t%v\t%v\t%v\t%v\t%.2f\t%.2f\t%v\n",
+			p.pid, p.username, status, p.rss, p.vms, p.minflt, p.majflt, p.pCPU, p.pMem, p.cmd); err != nil {
+			return err
+		}
+	}
+	return w.Flush()
 }
 
 func (n *nodeCollection) networkInterfaces() error {
-	f, err := os.Create(filepath.Join(n.nodeDir, "network_interface.json"))
+	result, err := net.Interfaces()
 	if err != nil {
-		return fmt.Errorf("unable to create file to write network interface output to: %v", err)
+		return fmt.Errorf("unable to fetch network Interfaces: %w", err)
 	}
-	defer f.Close() //nolint
 
-	is, err := net.Interfaces()
-	if err != nil {
-		return fmt.Errorf("unable to fetch network Interfaces: %v", err)
-	}
-	out, err := json.Marshal(is)
-	if err != nil {
-		return fmt.Errorf("unable to convert to json representation: %v", err)
+	if len(result) == 0 {
+		return nil // don't write a file on an unsupported platform
 	}
-	fmt.Fprintln(f, string(out))
-
-	return nil
+	return writeJSON(result, filepath.Join(n.nodeDir, "network_interface.json"))
 }
 
 type connStat struct {
@@ -215,29 +219,21 @@ var typeMap = map[uint32]string{
 }
 
 func (n *nodeCollection) activeConnections() error {
-	f, err := os.Create(filepath.Join(n.nodeDir, "connections.json"))
-	if err != nil {
-		return fmt.Errorf("unable to create file to write network interface output to: %v", err)
-	}
-	defer f.Close() //nolint
-
 	cs, err := net.Connections("all")
 	if err != nil {
-		return fmt.Errorf("unable to fetch network Interfaces: %v", err)
+		return fmt.Errorf("unable to fetch network interfaces: %w", err)
 	}
 
-	ret := make([]connStat, 0, len(cs))
+	result := make([]connStat, 0, len(cs))
 	for i := range cs {
 		st := addLabelToConnection(&cs[i])
-		ret = append(ret, st)
-	}
-	out, err := json.Marshal(ret)
-	if err != nil {
-		return fmt.Errorf("unable to convert to json representation: %v", err)
+		result = append(result, st)
 	}
-	fmt.Fprintln(f, string(out))
 
-	return nil
+	if len(result) == 0 {
+		return nil // don't write a file on an unsupported platform
+	}
+	return writeJSON(result, filepath.Join(n.nodeDir, "connections.json"))
 }
 
 // Replace uint32 label to human readable string label.
diff --git a/pkg/binary/envoy/fetch.go b/pkg/binary/envoy/fetch.go
index 35a2eaa..872a61e 100644
--- a/pkg/binary/envoy/fetch.go
+++ b/pkg/binary/envoy/fetch.go
@@ -26,7 +26,6 @@ import (
 
 	"github.com/mholt/archiver/v3"
 	"github.com/schollz/progressbar/v3"
-	"github.com/tetratelabs/log"
 
 	"github.com/tetratelabs/getenvoy/pkg/globals"
 	"github.com/tetratelabs/getenvoy/pkg/manifest"
@@ -59,7 +58,6 @@ func FetchIfNeeded(o *globals.GlobalOpts, reference string) (string, error) {
 			return "", fmt.Errorf("unable to create directory %q: %w", platformDirectory, err)
 		}
 
-		log.Debugf("fetching %v from %v", ref, binaryLocation)
 		err = fetchEnvoy(platformDirectory, binaryLocation)
 		if err != nil {
 			return "", err
@@ -137,7 +135,6 @@ func extractEnvoy(dst, tarball string) error {
 		return err
 	}
 	envoyFilepath := filepath.Join(dst, envoyLocation)
-	log.Debugf("checking for binary at %v", envoyFilepath)
 	if _, err := os.Stat(envoyFilepath); os.IsNotExist(err) {
 		return errors.New("no Envoy binary in downloaded tarball")
 	}
diff --git a/pkg/binary/envoy/procattr.go b/pkg/binary/envoy/procattr.go
index 617e382..fef5bea 100644
--- a/pkg/binary/envoy/procattr.go
+++ b/pkg/binary/envoy/procattr.go
@@ -18,13 +18,10 @@ package envoy
 
 import (
 	"syscall"
-
-	"github.com/tetratelabs/log"
 )
 
 func sysProcAttr() *syscall.SysProcAttr {
-	log.Warn("Running on a non-Linux system, cannot set child process kill signal. " +
-		"Some cases where this process terminates before the Envoy child process may not be handled gracefully.")
+	// TODO: Add a test for "getenvoy run" kill -9, that checks if the child envoy process remains running.
 	return &syscall.SysProcAttr{
 		Setpgid: true, // equivalent to setpgrp() syscall
 	}
diff --git a/pkg/binary/envoy/run.go b/pkg/binary/envoy/run.go
index c749af8..f898ded 100644
--- a/pkg/binary/envoy/run.go
+++ b/pkg/binary/envoy/run.go
@@ -23,8 +23,6 @@ import (
 	"strings"
 	"syscall"
 	"time"
-
-	"github.com/tetratelabs/log"
 )
 
 // Run execs the binary at the path with the args passed. It is a blocking function that can be terminated via SIGINT.
@@ -44,8 +42,8 @@ func (r *Runtime) Run(ctx context.Context, args []string) error {
 	}
 
 	// Log for the information of users and also for us to have a reliable parsing in e2e tests.
-	log.Infof("cd %s\n", cmd.Dir)
-	log.Infof("%s %s\n", r.opts.EnvoyPath, strings.Join(args, " "))
+	r.opts.Log.Printf("cd %s\n", cmd.Dir)
+	r.opts.Log.Printf("%s %s\n", r.opts.EnvoyPath, strings.Join(args, " "))
 	if err := cmd.Start(); err != nil {
 		return fmt.Errorf("unable to start Envoy process: %w", err)
 	}
@@ -55,7 +53,7 @@ func (r *Runtime) Run(ctx context.Context, args []string) error {
 	defer waitCancel()
 	r.FakeInterrupt = sigCancel
 
-	go waitForExit(cmd, waitCancel) // waits in a goroutine. We may need to kill the process if a signal occurs first.
+	go r.waitForExit(waitCancel) // waits in a goroutine. We may need to kill the process if a signal occurs first.
 
 	awaitAdminAddress(sigCtx, r)
 
@@ -80,7 +78,7 @@ func awaitAdminAddress(sigCtx context.Context, r *Runtime) {
 	for i := 0; i < 10 && sigCtx.Err() == nil; i++ {
 		adminAddress, adminErr := r.GetAdminAddress()
 		if adminErr == nil {
-			log.Infof("discovered admin address: %v", adminAddress)
+			r.opts.Log.Printf("discovered admin address: %v", adminAddress)
 			return
 		}
 		time.Sleep(200 * time.Millisecond)
@@ -102,13 +100,13 @@ func (r *Runtime) AppendArgs(args []string) {
 	r.cmd.Args = append(r.cmd.Args, args...)
 }
 
-func waitForExit(cmd *exec.Cmd, cancel context.CancelFunc) {
+func (r *Runtime) waitForExit(cancel context.CancelFunc) {
 	defer cancel()
-	if err := cmd.Wait(); err != nil {
-		if cmd.ProcessState.ExitCode() == -1 {
-			log.Infof("Envoy process (PID=%d) terminated via %v", cmd.Process.Pid, err)
+	if err := r.cmd.Wait(); err != nil {
+		if r.cmd.ProcessState.ExitCode() == -1 {
+			r.opts.Log.Printf("Envoy process (PID=%d) terminated via %v", r.cmd.Process.Pid, err)
 		} else {
-			log.Infof("Envoy process (PID=%d) terminated with an error: %v", cmd.Process.Pid, err)
+			r.opts.Log.Printf("Envoy process (PID=%d) terminated with an error: %v", r.cmd.Process.Pid, err)
 		}
 	}
 }
diff --git a/pkg/binary/envoy/runtime.go b/pkg/binary/envoy/runtime.go
index 6c1d017..8c7f908 100644
--- a/pkg/binary/envoy/runtime.go
+++ b/pkg/binary/envoy/runtime.go
@@ -54,6 +54,11 @@ func (r *Runtime) GetWorkingDir() string {
 	return r.opts.WorkingDir
 }
 
+// LogDebug is used by the debug package to warn users about a feature failure, such as lsof.
+func (r *Runtime) LogDebug(format string, v ...interface{}) {
+	r.opts.DebugLog.Printf(format, v...)
+}
+
 // GetAdminAddress returns the current admin address in host:port format, or empty if not yet available.
 // Exported for debug.EnableEnvoyAdminDataCollection, which is always on due to debug.EnableAll.
 func (r *Runtime) GetAdminAddress() (string, error) {
diff --git a/pkg/binary/envoy/termination.go b/pkg/binary/envoy/termination.go
index ab1f46c..e23973c 100644
--- a/pkg/binary/envoy/termination.go
+++ b/pkg/binary/envoy/termination.go
@@ -21,32 +21,30 @@ import (
 	"syscall"
 
 	"github.com/mholt/archiver/v3"
-	"github.com/tetratelabs/log"
 )
 
 func (r *Runtime) handleTermination() {
-	cmd := r.cmd
+	defer r.interrupt() // Ensure the SIGINT forwards to Envoy even if a pre-termination hook panics
 
-	defer interrupt(cmd.Process) // Ensure the SIGINT forwards to Envoy even if a pre-termination hook panics
-
-	log.Infof("GetEnvoy process (PID=%d) received SIGINT", os.Getpid())
+	r.opts.Log.Printf("GetEnvoy process (PID=%d) received SIGINT", os.Getpid())
 	// Execute all registered preTermination functions
 	for _, f := range r.preTermination {
 		if err := f(); err != nil {
-			log.Error(err.Error())
+			r.LogDebug("failed to handle pre termination: %v", err)
 		}
 	}
 }
 
-func interrupt(p *os.Process) {
-	log.Infof("Sending Envoy process (PID=%d) SIGINT", p.Pid)
+func (r *Runtime) interrupt() {
+	p := r.cmd.Process
+	r.opts.Log.Printf("Sending Envoy process (PID=%d) SIGINT", p.Pid)
 	_ = p.Signal(syscall.SIGINT)
 }
 
 func (r *Runtime) handlePostTermination() error {
 	for _, f := range r.postTermination {
 		if err := f(); err != nil {
-			log.Errorf("failed to handle post termination: %v", err)
+			r.LogDebug("failed to handle post termination: %v", err)
 		}
 	}
 
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index 0a8e0fa..21e4379 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -17,6 +17,7 @@ package cmd
 import (
 	"errors"
 	"fmt"
+	"log"
 	"os"
 	"path/filepath"
 	"strconv"
@@ -87,6 +88,13 @@ func InitializeRunOpts(o *globals.GlobalOpts, reference string) error {
 		}
 		runOpts.WorkingDir = workingDir
 	}
+	if runOpts.Log == nil { // not overridden for tests
+		runOpts.Log = log.New(os.Stdout, "run: ", log.LstdFlags)
+	}
+	if runOpts.DebugLog == nil { // not overridden for tests
+		// All debug features are optional. If there is any unexpected failure, log as "debug" to stdout.
+		runOpts.DebugLog = log.New(os.Stdout, "debug: ", log.LstdFlags)
+	}
 	return nil
 }
 
@@ -96,6 +104,8 @@ func Run(o *globals.GlobalOpts, cmd *cobra.Command, args []string) error {
 	r := envoy.NewRuntime(&o.RunOpts)
 	r.Out = cmd.OutOrStdout()
 	r.Err = cmd.ErrOrStderr()
+
 	debug.EnableAll(r)
+
 	return r.Run(cmd.Context(), args)
 }
diff --git a/pkg/globals/globals.go b/pkg/globals/globals.go
index 6669b49..bb0a996 100644
--- a/pkg/globals/globals.go
+++ b/pkg/globals/globals.go
@@ -14,6 +14,8 @@
 
 package globals
 
+import "log"
+
 // RunOpts support invocations of "getenvoy run" and "getenvoy extension run"
 type RunOpts struct {
 	// EnvoyPath is the exec.Cmd path to "envoy". Defaults to "$HomeDir/builds/$flavor/$version/$platform/bin/envoy"
@@ -22,6 +24,10 @@ type RunOpts struct {
 	// Upon termination, this directory is archived as "../$(basename $WorkingDir).tar.gz"
 	// Defaults to "$HomeDir/debug/$epochtime"
 	WorkingDir string
+	// Log generates output users should be aware of. Defaults to os.Stdout with "run: " prefix.
+	Log *log.Logger
+	// DebugLog generates output for debug features such as access logging. Defaults to os.Stdout with "debug: " prefix.
+	DebugLog *log.Logger
 }
 
 // GlobalOpts represents options that affect more than one getenvoy commands.
diff --git a/pkg/manifest/locate.go b/pkg/manifest/locate.go
index 31c2ccf..2893d09 100644
--- a/pkg/manifest/locate.go
+++ b/pkg/manifest/locate.go
@@ -19,7 +19,6 @@ import (
 	"io"
 	"net/http"
 
-	"github.com/tetratelabs/log"
 	"google.golang.org/protobuf/encoding/protojson"
 
 	"github.com/tetratelabs/getenvoy/api"
@@ -28,7 +27,6 @@ import (
 
 // FetchManifest returns a manifest from a remote URL. eg global.manifestURL.
 func FetchManifest(manifestURL string) (*api.Manifest, error) {
-	log.Debugf("retrieving manifest %s", manifestURL)
 	// #nosec => This is by design, users can call out to wherever they like!
 	resp, err := transport.Get(manifestURL)
 	if err != nil {


Test patch:
diff --git a/pkg/binary/envoy/debug/admin_test.go b/pkg/binary/envoy/debug/admin_test.go
index 56e7fbb..db38ccb 100644
--- a/pkg/binary/envoy/debug/admin_test.go
+++ b/pkg/binary/envoy/debug/admin_test.go
@@ -42,7 +42,7 @@ func TestEnableEnvoyAdminDataCollection(t *testing.T) {
 	require.NoError(t, err)
 
 	workingDir := envoytest.RunAndTerminateWithDebug(t, debugDir,
-		EnableEnvoyAdminDataCollection, `--admin-address-path`, adminPath)
+		enableEnvoyAdminDataCollection, `--admin-address-path`, adminPath)
 
 	for _, filename := range adminAPIPaths {
 		path := filepath.Join(workingDir, filename)
diff --git a/pkg/binary/envoy/debug/log_test.go b/pkg/binary/envoy/debug/log_test.go
index 75a7690..9969b07 100644
--- a/pkg/binary/envoy/debug/log_test.go
+++ b/pkg/binary/envoy/debug/log_test.go
@@ -28,7 +28,7 @@ func TestEnableEnvoyLogCollection(t *testing.T) {
 	debugDir, removeDebugDir := morerequire.RequireNewTempDir(t)
 	defer removeDebugDir()
 
-	workingDir := envoytest.RunAndTerminateWithDebug(t, debugDir, EnableEnvoyLogCollection)
+	workingDir := envoytest.RunAndTerminateWithDebug(t, debugDir, enableEnvoyLogCollection)
 
 	for _, filename := range []string{"logs/access.log", "logs/error.log"} {
 		require.FileExists(t, filepath.Join(workingDir, filename))
diff --git a/pkg/binary/envoy/debug/lsof_test.go b/pkg/binary/envoy/debug/lsof_test.go
index 0a2fee9..2a79048 100644
--- a/pkg/binary/envoy/debug/lsof_test.go
+++ b/pkg/binary/envoy/debug/lsof_test.go
@@ -31,16 +31,16 @@ func TestEnableOpenFilesDataCollection(t *testing.T) {
 	debugDir, removeDebugDir := morerequire.RequireNewTempDir(t)
 	defer removeDebugDir()
 
-	workingDir := envoytest.RunAndTerminateWithDebug(t, debugDir, EnableOpenFilesDataCollection)
+	workingDir := envoytest.RunAndTerminateWithDebug(t, debugDir, enableOpenFilesDataCollection)
 
 	file := "lsof/lsof.json"
 	path := filepath.Join(workingDir, file)
-	f, err := os.Stat(path)
-	require.NoError(t, err, "error stating %v", path)
 
 	if runtime.GOOS == `darwin` { // process.OpenFiles in unsupported, so this feature won't work
-		require.Empty(t, f.Size(), "file %v was not empty", path)
+		require.NoFileExists(t, path)
 	} else {
+		f, err := os.Stat(path)
+		require.NoError(t, err, "error stating %v", path)
 		require.NotEmpty(t, f.Size(), "file %v was empty", path)
 		raw, err := os.ReadFile(path)
 		require.NoError(t, err, "error reading file %v", path)
diff --git a/pkg/binary/envoy/debug/node_test.go b/pkg/binary/envoy/debug/node_test.go
index cb0c298..faa9fe1 100644
--- a/pkg/binary/envoy/debug/node_test.go
+++ b/pkg/binary/envoy/debug/node_test.go
@@ -31,7 +31,7 @@ func TestEnableNodeCollection(t *testing.T) {
 	debugDir, removeDebugDir := morerequire.RequireNewTempDir(t)
 	defer removeDebugDir()
 
-	workingDir := envoytest.RunAndTerminateWithDebug(t, debugDir, EnableNodeCollection)
+	workingDir := envoytest.RunAndTerminateWithDebug(t, debugDir, enableNodeCollection)
 
 	files := [...]string{"node/ps.txt", "node/network_interface.json", "node/connections.json"}
 	for _, file := range files {
@@ -52,7 +52,7 @@ func TestEnableNodeCollection(t *testing.T) {
 
 			err = json.Unmarshal(raw, &is)
 			require.NoError(t, err, "error to unmarshal json string, %v: \"%v\"", err, raw)
-			require.NotEmpty(t, len(is), "unmarshaled content is empty, expected to be a non-empty array: \"%v\"", raw)
+			require.NotEmpty(t, len(is), "unmarshalled content is empty, expected to be a non-empty array: \"%v\"", raw)
 		}
 	}
 }
diff --git a/pkg/binary/envoy/run_test.go b/pkg/binary/envoy/run_test.go
index 886421e..9ee1b8e 100644
--- a/pkg/binary/envoy/run_test.go
+++ b/pkg/binary/envoy/run_test.go
@@ -15,6 +15,8 @@
 package envoy_test
 
 import (
+	"io"
+	"log"
 	"os"
 	"path/filepath"
 	"syscall"
@@ -71,10 +73,10 @@ func TestRuntime_Run(t *testing.T) {
 
 			fakeTimestamp := "1619574747231823000"
 			workingDir := filepath.Join(debugDir, fakeTimestamp)
+			fakeLogger := log.New(io.Discard, "", 0)
+			o := &globals.RunOpts{EnvoyPath: fakeEnvoy, WorkingDir: workingDir, Log: fakeLogger, DebugLog: fakeLogger}
 			require.NoError(t, os.MkdirAll(workingDir, 0750))
 
-			o := &globals.RunOpts{EnvoyPath: fakeEnvoy, WorkingDir: workingDir}
-
 			// This ensures functions are called in the correct order
 			r, preStartCalled, preTerminationCalled, postTerminationCalled := newRuntimeWithMockFunctions(t, o)
 
diff --git a/pkg/binary/envoytest/util.go b/pkg/binary/envoytest/util.go
index 0d933b9..f26083d 100644
--- a/pkg/binary/envoytest/util.go
+++ b/pkg/binary/envoytest/util.go
@@ -16,6 +16,8 @@ package envoytest
 
 import (
 	"context"
+	"io"
+	"log"
 	"os"
 	"path/filepath"
 	"testing"
@@ -30,18 +32,21 @@ import (
 )
 
 // RunAndTerminateWithDebug is like RequireRunTerminate, except returns a directory populated by the debug plugin.
-func RunAndTerminateWithDebug(t *testing.T, debugDir string, debug func(r *envoy.Runtime), args ...string) string {
+func RunAndTerminateWithDebug(t *testing.T, debugDir string, debug func(r *envoy.Runtime) error, args ...string) string {
 	fakeEnvoy, removeFakeEnvoy := morerequire.RequireCaptureScript(t, "envoy")
 	defer removeFakeEnvoy()
 
 	fakeTimestamp := "1619574747231823000"
-	o := &globals.RunOpts{EnvoyPath: fakeEnvoy, WorkingDir: filepath.Join(debugDir, fakeTimestamp)}
+	workingDir := filepath.Join(debugDir, fakeTimestamp)
+	fakeLogger := log.New(io.Discard, "", 0)
+	o := &globals.RunOpts{EnvoyPath: fakeEnvoy, WorkingDir: workingDir, Log: fakeLogger, DebugLog: fakeLogger}
 	// InitializeRunOpts creates this directory in a real command run
 	require.NoError(t, os.MkdirAll(o.WorkingDir, 0750))
 
 	r := envoy.NewRuntime(o)
 
-	debug(r)
+	e := debug(r)
+	require.NoError(t, e)
 
 	RequireRunTerminate(t, nil, r, args...)
 	RequireRestoreWorkingDir(t, o.WorkingDir, r)
diff --git a/test/e2e/getenvoy_run_test.go b/test/e2e/getenvoy_run_test.go
index aa6946c..8ead25c 100644
--- a/test/e2e/getenvoy_run_test.go
+++ b/test/e2e/getenvoy_run_test.go
@@ -16,6 +16,7 @@ package e2e_test
 
 import (
 	"io"
+	"log"
 	"os"
 	"path/filepath"
 	"regexp"
@@ -23,7 +24,6 @@ import (
 	"time"
 
 	"github.com/stretchr/testify/require"
-	"github.com/tetratelabs/log"
 
 	reference "github.com/tetratelabs/getenvoy/pkg"
 	"github.com/tetratelabs/getenvoy/pkg/binary/envoytest"
@@ -57,7 +57,7 @@ func TestGetEnvoyRun(t *testing.T) {
 	envoyWorkingDir := requireEnvoyWorkingDir(t, stdout, c)
 	requireEnvoyReady(t, envoyWorkingDir, stderr, c)
 
-	log.Infof(`stopping Envoy after running [%v]`, c)
+	log.Printf(`stopping Envoy after running [%v]`, c)
 	terminate()
 	deferredTerminate = nil
 
@@ -66,7 +66,7 @@ func TestGetEnvoyRun(t *testing.T) {
 
 func requireEnvoyWorkingDir(t *testing.T, stdout io.Reader, c interface{}) string {
 	stdoutLines := e2e.StreamLines(stdout).Named("stdout")
-	log.Infof(`waiting for GetEnvoy to log working directory after running [%v]`, c)
+	log.Printf(`waiting for GetEnvoy to log working directory after running [%v]`, c)
 	workingDirectoryPattern := regexp.MustCompile(`cd (.*)`)
 	line, err := stdoutLines.FirstMatch(workingDirectoryPattern).Wait(10 * time.Minute) // give time to compile the extension
 	require.NoError(t, err, `error parsing working directory from stdout of [%v]`, c)
@@ -76,7 +76,7 @@ func requireEnvoyWorkingDir(t *testing.T, stdout io.Reader, c interface{}) strin
 func requireEnvoyReady(t *testing.T, envoyWorkingDir string, stderr io.Reader, c interface{}) utilenvoy.AdminAPI {
 	stderrLines := e2e.StreamLines(stderr).Named("stderr")
 
-	log.Infof(`waiting for Envoy start-up to complete after running [%v]`, c)
+	log.Printf(`waiting for Envoy start-up to complete after running [%v]`, c)
 	_, err := stderrLines.FirstMatch(regexp.MustCompile(`starting main dispatch loop`)).Wait(1 * time.Minute)
 	require.NoError(t, err, `error parsing startup from stderr of [%v]`, c)
 
@@ -84,7 +84,7 @@ func requireEnvoyReady(t *testing.T, envoyWorkingDir string, stderr io.Reader, c
 	adminAddress, err := os.ReadFile(adminAddressPath) //nolint:gosec
 	require.NoError(t, err, `error reading admin address file %q after running [%v]`, adminAddressPath, c)
 
-	log.Infof(`waiting for Envoy client to connect after running [%v]`, c)
+	log.Printf(`waiting for Envoy client to connect after running [%v]`, c)
 	envoyClient, err := utilenvoy.NewClient(string(adminAddress))
 	require.NoError(t, err, `error from envoy client %s after running [%v]`, adminAddress, c)
 	require.Eventually(t, func() bool {