Browse code

vendor: github.com/prometheus/client_golang v1.12.1, procfs v0.7.3

full diff: https://github.com/prometheus/client_golang/compare/v1.6.0...v1.12.1
full diff: https://github.com/prometheus/procfs/compare/v0.0.11...v0.7.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2022/06/29 21:55:36
Showing 82 changed files
... ...
@@ -171,8 +171,6 @@ replace (
171 171
 	github.com/armon/go-radix => github.com/armon/go-radix v0.0.0-20150105235045-e39d623f12e8
172 172
 	github.com/hashicorp/go-msgpack => github.com/hashicorp/go-msgpack v0.0.0-20140221154404-71c2886f5a67
173 173
 	github.com/hashicorp/serf => github.com/hashicorp/serf v0.7.1-0.20160317193612-598c54895cc5
174
-	github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.6.0
175
-	github.com/prometheus/procfs => github.com/prometheus/procfs v0.0.11
176 174
 )
177 175
 
178 176
 // Removes etcd dependency
... ...
@@ -114,7 +114,9 @@ github.com/akutz/gosync v0.1.0 h1:naxPT/aDYDh79PMwM3XmencmNQeYmpNFSZy4ZE9zIW0=
114 114
 github.com/akutz/gosync v0.1.0/go.mod h1:I8I4aiqJI1nqaeYOOB1WS+CgRJVVPqhct9Y4njywM84=
115 115
 github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A=
116 116
 github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw=
117
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
117 118
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
119
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
118 120
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
119 121
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
120 122
 github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
... ...
@@ -133,6 +135,8 @@ github.com/aws/aws-sdk-go v1.31.6 h1:nKjQbpXhdImctBh1e0iLg9iQW/X297LPPuY/9f92R2k
133 133
 github.com/aws/aws-sdk-go v1.31.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
134 134
 github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
135 135
 github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
136
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
137
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
136 138
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
137 139
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
138 140
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
... ...
@@ -347,6 +351,7 @@ github.com/deckarep/golang-set v0.0.0-20141123011944-ef32fa3046d9/go.mod h1:93vs
347 347
 github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
348 348
 github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
349 349
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
350
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
350 351
 github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
351 352
 github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
352 353
 github.com/docker/cli v20.10.13+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
... ...
@@ -425,8 +430,10 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9
425 425
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
426 426
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
427 427
 github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
428
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
428 429
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
429 430
 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
431
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
430 432
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
431 433
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
432 434
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
... ...
@@ -469,6 +476,7 @@ github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/
469 469
 github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
470 470
 github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
471 471
 github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
472
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
472 473
 github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
473 474
 github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
474 475
 github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
... ...
@@ -661,7 +669,6 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqo
661 661
 github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
662 662
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
663 663
 github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
664
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
665 664
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
666 665
 github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
667 666
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
... ...
@@ -780,6 +787,7 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
780 780
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
781 781
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
782 782
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
783
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
783 784
 github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
784 785
 github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
785 786
 github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
... ...
@@ -852,6 +860,7 @@ github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee h1:P6U24L02WMfj9ym
852 852
 github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee/go.mod h1:3uODdxMgOaPYeWU7RzZLxVtJHZ/x1f/iHkBZuKJDzuY=
853 853
 github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
854 854
 github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
855
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
855 856
 github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
856 857
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
857 858
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
... ...
@@ -860,21 +869,45 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
860 860
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
861 861
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
862 862
 github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
863
-github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A=
864
-github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4=
863
+github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
864
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
865
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
866
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
867
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
868
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
869
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
870
+github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
871
+github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
865 872
 github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
873
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
874
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
866 875
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
867 876
 github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
868 877
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
869 878
 github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
870
-github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
879
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
880
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
881
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
882
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
871 883
 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
872 884
 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
873 885
 github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
874 886
 github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
875 887
 github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
876
-github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI=
877
-github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
888
+github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
889
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
890
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
891
+github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
892
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
893
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
894
+github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
895
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
896
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
897
+github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
898
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
899
+github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
900
+github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
901
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
878 902
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
879 903
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
880 904
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
... ...
@@ -1151,6 +1184,7 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r
1151 1151
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
1152 1152
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
1153 1153
 golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
1154
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
1154 1155
 golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
1155 1156
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
1156 1157
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
... ...
@@ -1259,6 +1293,7 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w
1259 1259
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1260 1260
 golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1261 1261
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1262
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1262 1263
 golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1263 1264
 golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1264 1265
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
... ...
@@ -1287,12 +1322,12 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
1287 1287
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1288 1288
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1289 1289
 golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1290
-golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1291 1290
 golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1292 1291
 golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1293 1292
 golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1294 1293
 golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1295 1294
 golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1295
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1296 1296
 golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1297 1297
 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1298 1298
 golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
... ...
@@ -1331,6 +1366,7 @@ golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7w
1331 1331
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1332 1332
 golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1333 1333
 golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1334
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1334 1335
 golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1335 1336
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1336 1337
 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
... ...
@@ -1 +1 @@
1
-See [![go-doc](https://godoc.org/github.com/prometheus/client_golang/prometheus?status.svg)](https://godoc.org/github.com/prometheus/client_golang/prometheus).
1
+See [![Go Reference](https://pkg.go.dev/badge/github.com/prometheus/client_golang/prometheus.svg)](https://pkg.go.dev/github.com/prometheus/client_golang/prometheus).
2 2
deleted file mode 100644
... ...
@@ -1,29 +0,0 @@
1
-// Copyright 2019 The Prometheus Authors
2
-// Licensed under the Apache License, Version 2.0 (the "License");
3
-// you may not use this file except in compliance with the License.
4
-// You may obtain a copy of the License at
5
-//
6
-// http://www.apache.org/licenses/LICENSE-2.0
7
-//
8
-// Unless required by applicable law or agreed to in writing, software
9
-// distributed under the License is distributed on an "AS IS" BASIS,
10
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
-// See the License for the specific language governing permissions and
12
-// limitations under the License.
13
-
14
-// +build go1.12
15
-
16
-package prometheus
17
-
18
-import "runtime/debug"
19
-
20
-// readBuildInfo is a wrapper around debug.ReadBuildInfo for Go 1.12+.
21
-func readBuildInfo() (path, version, sum string) {
22
-	path, version, sum = "unknown", "unknown", "unknown"
23
-	if bi, ok := debug.ReadBuildInfo(); ok {
24
-		path = bi.Main.Path
25
-		version = bi.Main.Version
26
-		sum = bi.Main.Sum
27
-	}
28
-	return
29
-}
30 1
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+// Copyright 2021 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+package prometheus
14
+
15
+import "runtime/debug"
16
+
17
+// NewBuildInfoCollector is the obsolete version of collectors.NewBuildInfoCollector.
18
+// See there for documentation.
19
+//
20
+// Deprecated: Use collectors.NewBuildInfoCollector instead.
21
+func NewBuildInfoCollector() Collector {
22
+	path, version, sum := "unknown", "unknown", "unknown"
23
+	if bi, ok := debug.ReadBuildInfo(); ok {
24
+		path = bi.Main.Path
25
+		version = bi.Main.Version
26
+		sum = bi.Main.Sum
27
+	}
28
+	c := &selfCollector{MustNewConstMetric(
29
+		NewDesc(
30
+			"go_build_info",
31
+			"Build information about the main Go module.",
32
+			nil, Labels{"path": path, "version": version, "checksum": sum},
33
+		),
34
+		GaugeValue, 1)}
35
+	c.init(c.self)
36
+	return c
37
+}
0 38
deleted file mode 100644
... ...
@@ -1,22 +0,0 @@
1
-// Copyright 2019 The Prometheus Authors
2
-// Licensed under the Apache License, Version 2.0 (the "License");
3
-// you may not use this file except in compliance with the License.
4
-// You may obtain a copy of the License at
5
-//
6
-// http://www.apache.org/licenses/LICENSE-2.0
7
-//
8
-// Unless required by applicable law or agreed to in writing, software
9
-// distributed under the License is distributed on an "AS IS" BASIS,
10
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
-// See the License for the specific language governing permissions and
12
-// limitations under the License.
13
-
14
-// +build !go1.12
15
-
16
-package prometheus
17
-
18
-// readBuildInfo is a wrapper around debug.ReadBuildInfo for Go versions before
19
-// 1.12. Remove this whole file once the minimum supported Go version is 1.12.
20
-func readBuildInfo() (path, version, sum string) {
21
-	return "unknown", "unknown", "unknown"
22
-}
... ...
@@ -118,3 +118,11 @@ func (c *selfCollector) Describe(ch chan<- *Desc) {
118 118
 func (c *selfCollector) Collect(ch chan<- Metric) {
119 119
 	ch <- c.self
120 120
 }
121
+
122
+// collectorMetric is a metric that is also a collector.
123
+// Because of selfCollector, most (if not all) Metrics in
124
+// this package are also collectors.
125
+type collectorMetric interface {
126
+	Metric
127
+	Collector
128
+}
... ...
@@ -133,10 +133,14 @@ func (c *counter) Inc() {
133 133
 	atomic.AddUint64(&c.valInt, 1)
134 134
 }
135 135
 
136
-func (c *counter) Write(out *dto.Metric) error {
136
+func (c *counter) get() float64 {
137 137
 	fval := math.Float64frombits(atomic.LoadUint64(&c.valBits))
138 138
 	ival := atomic.LoadUint64(&c.valInt)
139
-	val := fval + float64(ival)
139
+	return fval + float64(ival)
140
+}
141
+
142
+func (c *counter) Write(out *dto.Metric) error {
143
+	val := c.get()
140 144
 
141 145
 	var exemplar *dto.Exemplar
142 146
 	if e := c.exemplar.Load(); e != nil {
... ...
@@ -163,7 +167,7 @@ func (c *counter) updateExemplar(v float64, l Labels) {
163 163
 // (e.g. number of HTTP requests, partitioned by response code and
164 164
 // method). Create instances with NewCounterVec.
165 165
 type CounterVec struct {
166
-	*metricVec
166
+	*MetricVec
167 167
 }
168 168
 
169 169
 // NewCounterVec creates a new CounterVec based on the provided CounterOpts and
... ...
@@ -176,11 +180,11 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
176 176
 		opts.ConstLabels,
177 177
 	)
178 178
 	return &CounterVec{
179
-		metricVec: newMetricVec(desc, func(lvs ...string) Metric {
179
+		MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
180 180
 			if len(lvs) != len(desc.variableLabels) {
181 181
 				panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
182 182
 			}
183
-			result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs), now: time.Now}
183
+			result := &counter{desc: desc, labelPairs: MakeLabelPairs(desc, lvs), now: time.Now}
184 184
 			result.init(result) // Init self-collection.
185 185
 			return result
186 186
 		}),
... ...
@@ -188,7 +192,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
188 188
 }
189 189
 
190 190
 // GetMetricWithLabelValues returns the Counter for the given slice of label
191
-// values (same order as the VariableLabels in Desc). If that combination of
191
+// values (same order as the variable labels in Desc). If that combination of
192 192
 // label values is accessed for the first time, a new Counter is created.
193 193
 //
194 194
 // It is possible to call this method without using the returned Counter to only
... ...
@@ -202,7 +206,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
202 202
 // Counter with the same label values is created later.
203 203
 //
204 204
 // An error is returned if the number of label values is not the same as the
205
-// number of VariableLabels in Desc (minus any curried labels).
205
+// number of variable labels in Desc (minus any curried labels).
206 206
 //
207 207
 // Note that for more than one label value, this method is prone to mistakes
208 208
 // caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
... ...
@@ -211,7 +215,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
211 211
 // with a performance overhead (for creating and processing the Labels map).
212 212
 // See also the GaugeVec example.
213 213
 func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
214
-	metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
214
+	metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
215 215
 	if metric != nil {
216 216
 		return metric.(Counter), err
217 217
 	}
... ...
@@ -219,19 +223,19 @@ func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
219 219
 }
220 220
 
221 221
 // GetMetricWith returns the Counter for the given Labels map (the label names
222
-// must match those of the VariableLabels in Desc). If that label map is
222
+// must match those of the variable labels in Desc). If that label map is
223 223
 // accessed for the first time, a new Counter is created. Implications of
224 224
 // creating a Counter without using it and keeping the Counter for later use are
225 225
 // the same as for GetMetricWithLabelValues.
226 226
 //
227 227
 // An error is returned if the number and names of the Labels are inconsistent
228
-// with those of the VariableLabels in Desc (minus any curried labels).
228
+// with those of the variable labels in Desc (minus any curried labels).
229 229
 //
230 230
 // This method is used for the same purpose as
231 231
 // GetMetricWithLabelValues(...string). See there for pros and cons of the two
232 232
 // methods.
233 233
 func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
234
-	metric, err := v.metricVec.getMetricWith(labels)
234
+	metric, err := v.MetricVec.GetMetricWith(labels)
235 235
 	if metric != nil {
236 236
 		return metric.(Counter), err
237 237
 	}
... ...
@@ -275,7 +279,7 @@ func (v *CounterVec) With(labels Labels) Counter {
275 275
 // registered with a given registry (usually the uncurried version). The Reset
276 276
 // method deletes all metrics, even if called on a curried vector.
277 277
 func (v *CounterVec) CurryWith(labels Labels) (*CounterVec, error) {
278
-	vec, err := v.curryWith(labels)
278
+	vec, err := v.MetricVec.CurryWith(labels)
279 279
 	if vec != nil {
280 280
 		return &CounterVec{vec}, err
281 281
 	}
... ...
@@ -20,6 +20,7 @@ import (
20 20
 	"strings"
21 21
 
22 22
 	"github.com/cespare/xxhash/v2"
23
+	//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
23 24
 	"github.com/golang/protobuf/proto"
24 25
 	"github.com/prometheus/common/model"
25 26
 
... ...
@@ -50,7 +51,7 @@ type Desc struct {
50 50
 	// constLabelPairs contains precalculated DTO label pairs based on
51 51
 	// the constant labels.
52 52
 	constLabelPairs []*dto.LabelPair
53
-	// VariableLabels contains names of labels for which the metric
53
+	// variableLabels contains names of labels for which the metric
54 54
 	// maintains variable values.
55 55
 	variableLabels []string
56 56
 	// id is a hash of the values of the ConstLabels and fqName. This
... ...
@@ -22,43 +22,10 @@ type expvarCollector struct {
22 22
 	exports map[string]*Desc
23 23
 }
24 24
 
25
-// NewExpvarCollector returns a newly allocated expvar Collector that still has
26
-// to be registered with a Prometheus registry.
25
+// NewExpvarCollector is the obsolete version of collectors.NewExpvarCollector.
26
+// See there for documentation.
27 27
 //
28
-// An expvar Collector collects metrics from the expvar interface. It provides a
29
-// quick way to expose numeric values that are already exported via expvar as
30
-// Prometheus metrics. Note that the data models of expvar and Prometheus are
31
-// fundamentally different, and that the expvar Collector is inherently slower
32
-// than native Prometheus metrics. Thus, the expvar Collector is probably great
33
-// for experiments and prototying, but you should seriously consider a more
34
-// direct implementation of Prometheus metrics for monitoring production
35
-// systems.
36
-//
37
-// The exports map has the following meaning:
38
-//
39
-// The keys in the map correspond to expvar keys, i.e. for every expvar key you
40
-// want to export as Prometheus metric, you need an entry in the exports
41
-// map. The descriptor mapped to each key describes how to export the expvar
42
-// value. It defines the name and the help string of the Prometheus metric
43
-// proxying the expvar value. The type will always be Untyped.
44
-//
45
-// For descriptors without variable labels, the expvar value must be a number or
46
-// a bool. The number is then directly exported as the Prometheus sample
47
-// value. (For a bool, 'false' translates to 0 and 'true' to 1). Expvar values
48
-// that are not numbers or bools are silently ignored.
49
-//
50
-// If the descriptor has one variable label, the expvar value must be an expvar
51
-// map. The keys in the expvar map become the various values of the one
52
-// Prometheus label. The values in the expvar map must be numbers or bools again
53
-// as above.
54
-//
55
-// For descriptors with more than one variable label, the expvar must be a
56
-// nested expvar map, i.e. where the values of the topmost map are maps again
57
-// etc. until a depth is reached that corresponds to the number of labels. The
58
-// leaves of that structure must be numbers or bools as above to serve as the
59
-// sample values.
60
-//
61
-// Anything that does not fit into the scheme above is silently ignored.
28
+// Deprecated: Use collectors.NewExpvarCollector instead.
62 29
 func NewExpvarCollector(exports map[string]*Desc) Collector {
63 30
 	return &expvarCollector{
64 31
 		exports: exports,
... ...
@@ -132,7 +132,7 @@ func (g *gauge) Write(out *dto.Metric) error {
132 132
 // (e.g. number of operations queued, partitioned by user and operation
133 133
 // type). Create instances with NewGaugeVec.
134 134
 type GaugeVec struct {
135
-	*metricVec
135
+	*MetricVec
136 136
 }
137 137
 
138 138
 // NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and
... ...
@@ -145,11 +145,11 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
145 145
 		opts.ConstLabels,
146 146
 	)
147 147
 	return &GaugeVec{
148
-		metricVec: newMetricVec(desc, func(lvs ...string) Metric {
148
+		MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
149 149
 			if len(lvs) != len(desc.variableLabels) {
150 150
 				panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
151 151
 			}
152
-			result := &gauge{desc: desc, labelPairs: makeLabelPairs(desc, lvs)}
152
+			result := &gauge{desc: desc, labelPairs: MakeLabelPairs(desc, lvs)}
153 153
 			result.init(result) // Init self-collection.
154 154
 			return result
155 155
 		}),
... ...
@@ -157,7 +157,7 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
157 157
 }
158 158
 
159 159
 // GetMetricWithLabelValues returns the Gauge for the given slice of label
160
-// values (same order as the VariableLabels in Desc). If that combination of
160
+// values (same order as the variable labels in Desc). If that combination of
161 161
 // label values is accessed for the first time, a new Gauge is created.
162 162
 //
163 163
 // It is possible to call this method without using the returned Gauge to only
... ...
@@ -172,7 +172,7 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
172 172
 // example.
173 173
 //
174 174
 // An error is returned if the number of label values is not the same as the
175
-// number of VariableLabels in Desc (minus any curried labels).
175
+// number of variable labels in Desc (minus any curried labels).
176 176
 //
177 177
 // Note that for more than one label value, this method is prone to mistakes
178 178
 // caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
... ...
@@ -180,7 +180,7 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
180 180
 // latter has a much more readable (albeit more verbose) syntax, but it comes
181 181
 // with a performance overhead (for creating and processing the Labels map).
182 182
 func (v *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) {
183
-	metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
183
+	metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
184 184
 	if metric != nil {
185 185
 		return metric.(Gauge), err
186 186
 	}
... ...
@@ -188,19 +188,19 @@ func (v *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) {
188 188
 }
189 189
 
190 190
 // GetMetricWith returns the Gauge for the given Labels map (the label names
191
-// must match those of the VariableLabels in Desc). If that label map is
191
+// must match those of the variable labels in Desc). If that label map is
192 192
 // accessed for the first time, a new Gauge is created. Implications of
193 193
 // creating a Gauge without using it and keeping the Gauge for later use are
194 194
 // the same as for GetMetricWithLabelValues.
195 195
 //
196 196
 // An error is returned if the number and names of the Labels are inconsistent
197
-// with those of the VariableLabels in Desc (minus any curried labels).
197
+// with those of the variable labels in Desc (minus any curried labels).
198 198
 //
199 199
 // This method is used for the same purpose as
200 200
 // GetMetricWithLabelValues(...string). See there for pros and cons of the two
201 201
 // methods.
202 202
 func (v *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) {
203
-	metric, err := v.metricVec.getMetricWith(labels)
203
+	metric, err := v.MetricVec.GetMetricWith(labels)
204 204
 	if metric != nil {
205 205
 		return metric.(Gauge), err
206 206
 	}
... ...
@@ -244,7 +244,7 @@ func (v *GaugeVec) With(labels Labels) Gauge {
244 244
 // registered with a given registry (usually the uncurried version). The Reset
245 245
 // method deletes all metrics, even if called on a curried vector.
246 246
 func (v *GaugeVec) CurryWith(labels Labels) (*GaugeVec, error) {
247
-	vec, err := v.curryWith(labels)
247
+	vec, err := v.MetricVec.CurryWith(labels)
248 248
 	if vec != nil {
249 249
 		return &GaugeVec{vec}, err
250 250
 	}
... ...
@@ -16,53 +16,209 @@ package prometheus
16 16
 import (
17 17
 	"runtime"
18 18
 	"runtime/debug"
19
-	"sync"
20 19
 	"time"
21 20
 )
22 21
 
23
-type goCollector struct {
22
+func goRuntimeMemStats() memStatsMetrics {
23
+	return memStatsMetrics{
24
+		{
25
+			desc: NewDesc(
26
+				memstatNamespace("alloc_bytes"),
27
+				"Number of bytes allocated and still in use.",
28
+				nil, nil,
29
+			),
30
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
31
+			valType: GaugeValue,
32
+		}, {
33
+			desc: NewDesc(
34
+				memstatNamespace("alloc_bytes_total"),
35
+				"Total number of bytes allocated, even if freed.",
36
+				nil, nil,
37
+			),
38
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
39
+			valType: CounterValue,
40
+		}, {
41
+			desc: NewDesc(
42
+				memstatNamespace("sys_bytes"),
43
+				"Number of bytes obtained from system.",
44
+				nil, nil,
45
+			),
46
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
47
+			valType: GaugeValue,
48
+		}, {
49
+			desc: NewDesc(
50
+				memstatNamespace("lookups_total"),
51
+				"Total number of pointer lookups.",
52
+				nil, nil,
53
+			),
54
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) },
55
+			valType: CounterValue,
56
+		}, {
57
+			desc: NewDesc(
58
+				memstatNamespace("mallocs_total"),
59
+				"Total number of mallocs.",
60
+				nil, nil,
61
+			),
62
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
63
+			valType: CounterValue,
64
+		}, {
65
+			desc: NewDesc(
66
+				memstatNamespace("frees_total"),
67
+				"Total number of frees.",
68
+				nil, nil,
69
+			),
70
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
71
+			valType: CounterValue,
72
+		}, {
73
+			desc: NewDesc(
74
+				memstatNamespace("heap_alloc_bytes"),
75
+				"Number of heap bytes allocated and still in use.",
76
+				nil, nil,
77
+			),
78
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
79
+			valType: GaugeValue,
80
+		}, {
81
+			desc: NewDesc(
82
+				memstatNamespace("heap_sys_bytes"),
83
+				"Number of heap bytes obtained from system.",
84
+				nil, nil,
85
+			),
86
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
87
+			valType: GaugeValue,
88
+		}, {
89
+			desc: NewDesc(
90
+				memstatNamespace("heap_idle_bytes"),
91
+				"Number of heap bytes waiting to be used.",
92
+				nil, nil,
93
+			),
94
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
95
+			valType: GaugeValue,
96
+		}, {
97
+			desc: NewDesc(
98
+				memstatNamespace("heap_inuse_bytes"),
99
+				"Number of heap bytes that are in use.",
100
+				nil, nil,
101
+			),
102
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
103
+			valType: GaugeValue,
104
+		}, {
105
+			desc: NewDesc(
106
+				memstatNamespace("heap_released_bytes"),
107
+				"Number of heap bytes released to OS.",
108
+				nil, nil,
109
+			),
110
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
111
+			valType: GaugeValue,
112
+		}, {
113
+			desc: NewDesc(
114
+				memstatNamespace("heap_objects"),
115
+				"Number of allocated objects.",
116
+				nil, nil,
117
+			),
118
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
119
+			valType: GaugeValue,
120
+		}, {
121
+			desc: NewDesc(
122
+				memstatNamespace("stack_inuse_bytes"),
123
+				"Number of bytes in use by the stack allocator.",
124
+				nil, nil,
125
+			),
126
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
127
+			valType: GaugeValue,
128
+		}, {
129
+			desc: NewDesc(
130
+				memstatNamespace("stack_sys_bytes"),
131
+				"Number of bytes obtained from system for stack allocator.",
132
+				nil, nil,
133
+			),
134
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
135
+			valType: GaugeValue,
136
+		}, {
137
+			desc: NewDesc(
138
+				memstatNamespace("mspan_inuse_bytes"),
139
+				"Number of bytes in use by mspan structures.",
140
+				nil, nil,
141
+			),
142
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
143
+			valType: GaugeValue,
144
+		}, {
145
+			desc: NewDesc(
146
+				memstatNamespace("mspan_sys_bytes"),
147
+				"Number of bytes used for mspan structures obtained from system.",
148
+				nil, nil,
149
+			),
150
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
151
+			valType: GaugeValue,
152
+		}, {
153
+			desc: NewDesc(
154
+				memstatNamespace("mcache_inuse_bytes"),
155
+				"Number of bytes in use by mcache structures.",
156
+				nil, nil,
157
+			),
158
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
159
+			valType: GaugeValue,
160
+		}, {
161
+			desc: NewDesc(
162
+				memstatNamespace("mcache_sys_bytes"),
163
+				"Number of bytes used for mcache structures obtained from system.",
164
+				nil, nil,
165
+			),
166
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
167
+			valType: GaugeValue,
168
+		}, {
169
+			desc: NewDesc(
170
+				memstatNamespace("buck_hash_sys_bytes"),
171
+				"Number of bytes used by the profiling bucket hash table.",
172
+				nil, nil,
173
+			),
174
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
175
+			valType: GaugeValue,
176
+		}, {
177
+			desc: NewDesc(
178
+				memstatNamespace("gc_sys_bytes"),
179
+				"Number of bytes used for garbage collection system metadata.",
180
+				nil, nil,
181
+			),
182
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
183
+			valType: GaugeValue,
184
+		}, {
185
+			desc: NewDesc(
186
+				memstatNamespace("other_sys_bytes"),
187
+				"Number of bytes used for other system allocations.",
188
+				nil, nil,
189
+			),
190
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
191
+			valType: GaugeValue,
192
+		}, {
193
+			desc: NewDesc(
194
+				memstatNamespace("next_gc_bytes"),
195
+				"Number of heap bytes when next garbage collection will take place.",
196
+				nil, nil,
197
+			),
198
+			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
199
+			valType: GaugeValue,
200
+		}, {
201
+			desc: NewDesc(
202
+				memstatNamespace("gc_cpu_fraction"),
203
+				"The fraction of this program's available CPU time used by the GC since the program started.",
204
+				nil, nil,
205
+			),
206
+			eval:    func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction },
207
+			valType: GaugeValue,
208
+		},
209
+	}
210
+}
211
+
212
+type baseGoCollector struct {
24 213
 	goroutinesDesc *Desc
25 214
 	threadsDesc    *Desc
26 215
 	gcDesc         *Desc
216
+	gcLastTimeDesc *Desc
27 217
 	goInfoDesc     *Desc
28
-
29
-	// ms... are memstats related.
30
-	msLast          *runtime.MemStats // Previously collected memstats.
31
-	msLastTimestamp time.Time
32
-	msMtx           sync.Mutex // Protects msLast and msLastTimestamp.
33
-	msMetrics       memStatsMetrics
34
-	msRead          func(*runtime.MemStats) // For mocking in tests.
35
-	msMaxWait       time.Duration           // Wait time for fresh memstats.
36
-	msMaxAge        time.Duration           // Maximum allowed age of old memstats.
37 218
 }
38 219
 
39
-// NewGoCollector returns a collector that exports metrics about the current Go
40
-// process. This includes memory stats. To collect those, runtime.ReadMemStats
41
-// is called. This requires to “stop the world”, which usually only happens for
42
-// garbage collection (GC). Take the following implications into account when
43
-// deciding whether to use the Go collector:
44
-//
45
-// 1. The performance impact of stopping the world is the more relevant the more
46
-// frequently metrics are collected. However, with Go1.9 or later the
47
-// stop-the-world time per metrics collection is very short (~25µs) so that the
48
-// performance impact will only matter in rare cases. However, with older Go
49
-// versions, the stop-the-world duration depends on the heap size and can be
50
-// quite significant (~1.7 ms/GiB as per
51
-// https://go-review.googlesource.com/c/go/+/34937).
52
-//
53
-// 2. During an ongoing GC, nothing else can stop the world. Therefore, if the
54
-// metrics collection happens to coincide with GC, it will only complete after
55
-// GC has finished. Usually, GC is fast enough to not cause problems. However,
56
-// with a very large heap, GC might take multiple seconds, which is enough to
57
-// cause scrape timeouts in common setups. To avoid this problem, the Go
58
-// collector will use the memstats from a previous collection if
59
-// runtime.ReadMemStats takes more than 1s. However, if there are no previously
60
-// collected memstats, or their collection is more than 5m ago, the collection
61
-// will block until runtime.ReadMemStats succeeds. (The problem might be solved
62
-// in Go1.13, see https://github.com/golang/go/issues/19812 for the related Go
63
-// issue.)
64
-func NewGoCollector() Collector {
65
-	return &goCollector{
220
+func newBaseGoCollector() baseGoCollector {
221
+	return baseGoCollector{
66 222
 		goroutinesDesc: NewDesc(
67 223
 			"go_goroutines",
68 224
 			"Number of goroutines that currently exist.",
... ...
@@ -75,243 +231,28 @@ func NewGoCollector() Collector {
75 75
 			"go_gc_duration_seconds",
76 76
 			"A summary of the pause duration of garbage collection cycles.",
77 77
 			nil, nil),
78
+		gcLastTimeDesc: NewDesc(
79
+			memstatNamespace("last_gc_time_seconds"),
80
+			"Number of seconds since 1970 of last garbage collection.",
81
+			nil, nil),
78 82
 		goInfoDesc: NewDesc(
79 83
 			"go_info",
80 84
 			"Information about the Go environment.",
81 85
 			nil, Labels{"version": runtime.Version()}),
82
-		msLast:    &runtime.MemStats{},
83
-		msRead:    runtime.ReadMemStats,
84
-		msMaxWait: time.Second,
85
-		msMaxAge:  5 * time.Minute,
86
-		msMetrics: memStatsMetrics{
87
-			{
88
-				desc: NewDesc(
89
-					memstatNamespace("alloc_bytes"),
90
-					"Number of bytes allocated and still in use.",
91
-					nil, nil,
92
-				),
93
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
94
-				valType: GaugeValue,
95
-			}, {
96
-				desc: NewDesc(
97
-					memstatNamespace("alloc_bytes_total"),
98
-					"Total number of bytes allocated, even if freed.",
99
-					nil, nil,
100
-				),
101
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
102
-				valType: CounterValue,
103
-			}, {
104
-				desc: NewDesc(
105
-					memstatNamespace("sys_bytes"),
106
-					"Number of bytes obtained from system.",
107
-					nil, nil,
108
-				),
109
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
110
-				valType: GaugeValue,
111
-			}, {
112
-				desc: NewDesc(
113
-					memstatNamespace("lookups_total"),
114
-					"Total number of pointer lookups.",
115
-					nil, nil,
116
-				),
117
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) },
118
-				valType: CounterValue,
119
-			}, {
120
-				desc: NewDesc(
121
-					memstatNamespace("mallocs_total"),
122
-					"Total number of mallocs.",
123
-					nil, nil,
124
-				),
125
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
126
-				valType: CounterValue,
127
-			}, {
128
-				desc: NewDesc(
129
-					memstatNamespace("frees_total"),
130
-					"Total number of frees.",
131
-					nil, nil,
132
-				),
133
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
134
-				valType: CounterValue,
135
-			}, {
136
-				desc: NewDesc(
137
-					memstatNamespace("heap_alloc_bytes"),
138
-					"Number of heap bytes allocated and still in use.",
139
-					nil, nil,
140
-				),
141
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
142
-				valType: GaugeValue,
143
-			}, {
144
-				desc: NewDesc(
145
-					memstatNamespace("heap_sys_bytes"),
146
-					"Number of heap bytes obtained from system.",
147
-					nil, nil,
148
-				),
149
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
150
-				valType: GaugeValue,
151
-			}, {
152
-				desc: NewDesc(
153
-					memstatNamespace("heap_idle_bytes"),
154
-					"Number of heap bytes waiting to be used.",
155
-					nil, nil,
156
-				),
157
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
158
-				valType: GaugeValue,
159
-			}, {
160
-				desc: NewDesc(
161
-					memstatNamespace("heap_inuse_bytes"),
162
-					"Number of heap bytes that are in use.",
163
-					nil, nil,
164
-				),
165
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
166
-				valType: GaugeValue,
167
-			}, {
168
-				desc: NewDesc(
169
-					memstatNamespace("heap_released_bytes"),
170
-					"Number of heap bytes released to OS.",
171
-					nil, nil,
172
-				),
173
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
174
-				valType: GaugeValue,
175
-			}, {
176
-				desc: NewDesc(
177
-					memstatNamespace("heap_objects"),
178
-					"Number of allocated objects.",
179
-					nil, nil,
180
-				),
181
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
182
-				valType: GaugeValue,
183
-			}, {
184
-				desc: NewDesc(
185
-					memstatNamespace("stack_inuse_bytes"),
186
-					"Number of bytes in use by the stack allocator.",
187
-					nil, nil,
188
-				),
189
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
190
-				valType: GaugeValue,
191
-			}, {
192
-				desc: NewDesc(
193
-					memstatNamespace("stack_sys_bytes"),
194
-					"Number of bytes obtained from system for stack allocator.",
195
-					nil, nil,
196
-				),
197
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
198
-				valType: GaugeValue,
199
-			}, {
200
-				desc: NewDesc(
201
-					memstatNamespace("mspan_inuse_bytes"),
202
-					"Number of bytes in use by mspan structures.",
203
-					nil, nil,
204
-				),
205
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
206
-				valType: GaugeValue,
207
-			}, {
208
-				desc: NewDesc(
209
-					memstatNamespace("mspan_sys_bytes"),
210
-					"Number of bytes used for mspan structures obtained from system.",
211
-					nil, nil,
212
-				),
213
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
214
-				valType: GaugeValue,
215
-			}, {
216
-				desc: NewDesc(
217
-					memstatNamespace("mcache_inuse_bytes"),
218
-					"Number of bytes in use by mcache structures.",
219
-					nil, nil,
220
-				),
221
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
222
-				valType: GaugeValue,
223
-			}, {
224
-				desc: NewDesc(
225
-					memstatNamespace("mcache_sys_bytes"),
226
-					"Number of bytes used for mcache structures obtained from system.",
227
-					nil, nil,
228
-				),
229
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
230
-				valType: GaugeValue,
231
-			}, {
232
-				desc: NewDesc(
233
-					memstatNamespace("buck_hash_sys_bytes"),
234
-					"Number of bytes used by the profiling bucket hash table.",
235
-					nil, nil,
236
-				),
237
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
238
-				valType: GaugeValue,
239
-			}, {
240
-				desc: NewDesc(
241
-					memstatNamespace("gc_sys_bytes"),
242
-					"Number of bytes used for garbage collection system metadata.",
243
-					nil, nil,
244
-				),
245
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
246
-				valType: GaugeValue,
247
-			}, {
248
-				desc: NewDesc(
249
-					memstatNamespace("other_sys_bytes"),
250
-					"Number of bytes used for other system allocations.",
251
-					nil, nil,
252
-				),
253
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
254
-				valType: GaugeValue,
255
-			}, {
256
-				desc: NewDesc(
257
-					memstatNamespace("next_gc_bytes"),
258
-					"Number of heap bytes when next garbage collection will take place.",
259
-					nil, nil,
260
-				),
261
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
262
-				valType: GaugeValue,
263
-			}, {
264
-				desc: NewDesc(
265
-					memstatNamespace("last_gc_time_seconds"),
266
-					"Number of seconds since 1970 of last garbage collection.",
267
-					nil, nil,
268
-				),
269
-				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.LastGC) / 1e9 },
270
-				valType: GaugeValue,
271
-			}, {
272
-				desc: NewDesc(
273
-					memstatNamespace("gc_cpu_fraction"),
274
-					"The fraction of this program's available CPU time used by the GC since the program started.",
275
-					nil, nil,
276
-				),
277
-				eval:    func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction },
278
-				valType: GaugeValue,
279
-			},
280
-		},
281 86
 	}
282 87
 }
283 88
 
284
-func memstatNamespace(s string) string {
285
-	return "go_memstats_" + s
286
-}
287
-
288 89
 // Describe returns all descriptions of the collector.
289
-func (c *goCollector) Describe(ch chan<- *Desc) {
90
+func (c *baseGoCollector) Describe(ch chan<- *Desc) {
290 91
 	ch <- c.goroutinesDesc
291 92
 	ch <- c.threadsDesc
292 93
 	ch <- c.gcDesc
94
+	ch <- c.gcLastTimeDesc
293 95
 	ch <- c.goInfoDesc
294
-	for _, i := range c.msMetrics {
295
-		ch <- i.desc
296
-	}
297 96
 }
298 97
 
299 98
 // Collect returns the current state of all metrics of the collector.
300
-func (c *goCollector) Collect(ch chan<- Metric) {
301
-	var (
302
-		ms   = &runtime.MemStats{}
303
-		done = make(chan struct{})
304
-	)
305
-	// Start reading memstats first as it might take a while.
306
-	go func() {
307
-		c.msRead(ms)
308
-		c.msMtx.Lock()
309
-		c.msLast = ms
310
-		c.msLastTimestamp = time.Now()
311
-		c.msMtx.Unlock()
312
-		close(done)
313
-	}()
314
-
99
+func (c *baseGoCollector) Collect(ch chan<- Metric) {
315 100
 	ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine()))
316 101
 	n, _ := runtime.ThreadCreateProfile(nil)
317 102
 	ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n))
... ...
@@ -326,71 +267,19 @@ func (c *goCollector) Collect(ch chan<- Metric) {
326 326
 	}
327 327
 	quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
328 328
 	ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), stats.PauseTotal.Seconds(), quantiles)
329
+	ch <- MustNewConstMetric(c.gcLastTimeDesc, GaugeValue, float64(stats.LastGC.UnixNano())/1e9)
329 330
 
330 331
 	ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1)
331
-
332
-	timer := time.NewTimer(c.msMaxWait)
333
-	select {
334
-	case <-done: // Our own ReadMemStats succeeded in time. Use it.
335
-		timer.Stop() // Important for high collection frequencies to not pile up timers.
336
-		c.msCollect(ch, ms)
337
-		return
338
-	case <-timer.C: // Time out, use last memstats if possible. Continue below.
339
-	}
340
-	c.msMtx.Lock()
341
-	if time.Since(c.msLastTimestamp) < c.msMaxAge {
342
-		// Last memstats are recent enough. Collect from them under the lock.
343
-		c.msCollect(ch, c.msLast)
344
-		c.msMtx.Unlock()
345
-		return
346
-	}
347
-	// If we are here, the last memstats are too old or don't exist. We have
348
-	// to wait until our own ReadMemStats finally completes. For that to
349
-	// happen, we have to release the lock.
350
-	c.msMtx.Unlock()
351
-	<-done
352
-	c.msCollect(ch, ms)
353 332
 }
354 333
 
355
-func (c *goCollector) msCollect(ch chan<- Metric, ms *runtime.MemStats) {
356
-	for _, i := range c.msMetrics {
357
-		ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms))
358
-	}
334
+func memstatNamespace(s string) string {
335
+	return "go_memstats_" + s
359 336
 }
360 337
 
361
-// memStatsMetrics provide description, value, and value type for memstat metrics.
338
+// memStatsMetrics provide description, evaluator, runtime/metrics name, and
339
+// value type for memstat metrics.
362 340
 type memStatsMetrics []struct {
363 341
 	desc    *Desc
364 342
 	eval    func(*runtime.MemStats) float64
365 343
 	valType ValueType
366 344
 }
367
-
368
-// NewBuildInfoCollector returns a collector collecting a single metric
369
-// "go_build_info" with the constant value 1 and three labels "path", "version",
370
-// and "checksum". Their label values contain the main module path, version, and
371
-// checksum, respectively. The labels will only have meaningful values if the
372
-// binary is built with Go module support and from source code retrieved from
373
-// the source repository (rather than the local file system). This is usually
374
-// accomplished by building from outside of GOPATH, specifying the full address
375
-// of the main package, e.g. "GO111MODULE=on go run
376
-// github.com/prometheus/client_golang/examples/random". If built without Go
377
-// module support, all label values will be "unknown". If built with Go module
378
-// support but using the source code from the local file system, the "path" will
379
-// be set appropriately, but "checksum" will be empty and "version" will be
380
-// "(devel)".
381
-//
382
-// This collector uses only the build information for the main module. See
383
-// https://github.com/povilasv/prommod for an example of a collector for the
384
-// module dependencies.
385
-func NewBuildInfoCollector() Collector {
386
-	path, version, sum := readBuildInfo()
387
-	c := &selfCollector{MustNewConstMetric(
388
-		NewDesc(
389
-			"go_build_info",
390
-			"Build information about the main Go module.",
391
-			nil, Labels{"path": path, "version": version, "checksum": sum},
392
-		),
393
-		GaugeValue, 1)}
394
-	c.init(c.self)
395
-	return c
396
-}
397 345
new file mode 100644
... ...
@@ -0,0 +1,107 @@
0
+// Copyright 2021 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+//go:build !go1.17
14
+// +build !go1.17
15
+
16
+package prometheus
17
+
18
+import (
19
+	"runtime"
20
+	"sync"
21
+	"time"
22
+)
23
+
24
+type goCollector struct {
25
+	base baseGoCollector
26
+
27
+	// ms... are memstats related.
28
+	msLast          *runtime.MemStats // Previously collected memstats.
29
+	msLastTimestamp time.Time
30
+	msMtx           sync.Mutex // Protects msLast and msLastTimestamp.
31
+	msMetrics       memStatsMetrics
32
+	msRead          func(*runtime.MemStats) // For mocking in tests.
33
+	msMaxWait       time.Duration           // Wait time for fresh memstats.
34
+	msMaxAge        time.Duration           // Maximum allowed age of old memstats.
35
+}
36
+
37
+// NewGoCollector is the obsolete version of collectors.NewGoCollector.
38
+// See there for documentation.
39
+//
40
+// Deprecated: Use collectors.NewGoCollector instead.
41
+func NewGoCollector() Collector {
42
+	return &goCollector{
43
+		base:      newBaseGoCollector(),
44
+		msLast:    &runtime.MemStats{},
45
+		msRead:    runtime.ReadMemStats,
46
+		msMaxWait: time.Second,
47
+		msMaxAge:  5 * time.Minute,
48
+		msMetrics: goRuntimeMemStats(),
49
+	}
50
+}
51
+
52
+// Describe returns all descriptions of the collector.
53
+func (c *goCollector) Describe(ch chan<- *Desc) {
54
+	c.base.Describe(ch)
55
+	for _, i := range c.msMetrics {
56
+		ch <- i.desc
57
+	}
58
+}
59
+
60
+// Collect returns the current state of all metrics of the collector.
61
+func (c *goCollector) Collect(ch chan<- Metric) {
62
+	var (
63
+		ms   = &runtime.MemStats{}
64
+		done = make(chan struct{})
65
+	)
66
+	// Start reading memstats first as it might take a while.
67
+	go func() {
68
+		c.msRead(ms)
69
+		c.msMtx.Lock()
70
+		c.msLast = ms
71
+		c.msLastTimestamp = time.Now()
72
+		c.msMtx.Unlock()
73
+		close(done)
74
+	}()
75
+
76
+	// Collect base non-memory metrics.
77
+	c.base.Collect(ch)
78
+
79
+	timer := time.NewTimer(c.msMaxWait)
80
+	select {
81
+	case <-done: // Our own ReadMemStats succeeded in time. Use it.
82
+		timer.Stop() // Important for high collection frequencies to not pile up timers.
83
+		c.msCollect(ch, ms)
84
+		return
85
+	case <-timer.C: // Time out, use last memstats if possible. Continue below.
86
+	}
87
+	c.msMtx.Lock()
88
+	if time.Since(c.msLastTimestamp) < c.msMaxAge {
89
+		// Last memstats are recent enough. Collect from them under the lock.
90
+		c.msCollect(ch, c.msLast)
91
+		c.msMtx.Unlock()
92
+		return
93
+	}
94
+	// If we are here, the last memstats are too old or don't exist. We have
95
+	// to wait until our own ReadMemStats finally completes. For that to
96
+	// happen, we have to release the lock.
97
+	c.msMtx.Unlock()
98
+	<-done
99
+	c.msCollect(ch, ms)
100
+}
101
+
102
+func (c *goCollector) msCollect(ch chan<- Metric, ms *runtime.MemStats) {
103
+	for _, i := range c.msMetrics {
104
+		ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms))
105
+	}
106
+}
0 107
new file mode 100644
... ...
@@ -0,0 +1,408 @@
0
+// Copyright 2021 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+//go:build go1.17
14
+// +build go1.17
15
+
16
+package prometheus
17
+
18
+import (
19
+	"math"
20
+	"runtime"
21
+	"runtime/metrics"
22
+	"strings"
23
+	"sync"
24
+
25
+	//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
26
+	"github.com/golang/protobuf/proto"
27
+	"github.com/prometheus/client_golang/prometheus/internal"
28
+	dto "github.com/prometheus/client_model/go"
29
+)
30
+
31
+type goCollector struct {
32
+	base baseGoCollector
33
+
34
+	// mu protects updates to all fields ensuring a consistent
35
+	// snapshot is always produced by Collect.
36
+	mu sync.Mutex
37
+
38
+	// rm... fields all pertain to the runtime/metrics package.
39
+	rmSampleBuf []metrics.Sample
40
+	rmSampleMap map[string]*metrics.Sample
41
+	rmMetrics   []collectorMetric
42
+
43
+	// With Go 1.17, the runtime/metrics package was introduced.
44
+	// From that point on, metric names produced by the runtime/metrics
45
+	// package could be generated from runtime/metrics names. However,
46
+	// these differ from the old names for the same values.
47
+	//
48
+	// This field exist to export the same values under the old names
49
+	// as well.
50
+	msMetrics memStatsMetrics
51
+}
52
+
53
+// NewGoCollector is the obsolete version of collectors.NewGoCollector.
54
+// See there for documentation.
55
+//
56
+// Deprecated: Use collectors.NewGoCollector instead.
57
+func NewGoCollector() Collector {
58
+	descriptions := metrics.All()
59
+
60
+	// Collect all histogram samples so that we can get their buckets.
61
+	// The API guarantees that the buckets are always fixed for the lifetime
62
+	// of the process.
63
+	var histograms []metrics.Sample
64
+	for _, d := range descriptions {
65
+		if d.Kind == metrics.KindFloat64Histogram {
66
+			histograms = append(histograms, metrics.Sample{Name: d.Name})
67
+		}
68
+	}
69
+	metrics.Read(histograms)
70
+	bucketsMap := make(map[string][]float64)
71
+	for i := range histograms {
72
+		bucketsMap[histograms[i].Name] = histograms[i].Value.Float64Histogram().Buckets
73
+	}
74
+
75
+	// Generate a Desc and ValueType for each runtime/metrics metric.
76
+	metricSet := make([]collectorMetric, 0, len(descriptions))
77
+	sampleBuf := make([]metrics.Sample, 0, len(descriptions))
78
+	sampleMap := make(map[string]*metrics.Sample, len(descriptions))
79
+	for i := range descriptions {
80
+		d := &descriptions[i]
81
+		namespace, subsystem, name, ok := internal.RuntimeMetricsToProm(d)
82
+		if !ok {
83
+			// Just ignore this metric; we can't do anything with it here.
84
+			// If a user decides to use the latest version of Go, we don't want
85
+			// to fail here. This condition is tested elsewhere.
86
+			continue
87
+		}
88
+
89
+		// Set up sample buffer for reading, and a map
90
+		// for quick lookup of sample values.
91
+		sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name})
92
+		sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1]
93
+
94
+		var m collectorMetric
95
+		if d.Kind == metrics.KindFloat64Histogram {
96
+			_, hasSum := rmExactSumMap[d.Name]
97
+			unit := d.Name[strings.IndexRune(d.Name, ':')+1:]
98
+			m = newBatchHistogram(
99
+				NewDesc(
100
+					BuildFQName(namespace, subsystem, name),
101
+					d.Description,
102
+					nil,
103
+					nil,
104
+				),
105
+				internal.RuntimeMetricsBucketsForUnit(bucketsMap[d.Name], unit),
106
+				hasSum,
107
+			)
108
+		} else if d.Cumulative {
109
+			m = NewCounter(CounterOpts{
110
+				Namespace: namespace,
111
+				Subsystem: subsystem,
112
+				Name:      name,
113
+				Help:      d.Description,
114
+			})
115
+		} else {
116
+			m = NewGauge(GaugeOpts{
117
+				Namespace: namespace,
118
+				Subsystem: subsystem,
119
+				Name:      name,
120
+				Help:      d.Description,
121
+			})
122
+		}
123
+		metricSet = append(metricSet, m)
124
+	}
125
+	return &goCollector{
126
+		base:        newBaseGoCollector(),
127
+		rmSampleBuf: sampleBuf,
128
+		rmSampleMap: sampleMap,
129
+		rmMetrics:   metricSet,
130
+		msMetrics:   goRuntimeMemStats(),
131
+	}
132
+}
133
+
134
+// Describe returns all descriptions of the collector.
135
+func (c *goCollector) Describe(ch chan<- *Desc) {
136
+	c.base.Describe(ch)
137
+	for _, i := range c.msMetrics {
138
+		ch <- i.desc
139
+	}
140
+	for _, m := range c.rmMetrics {
141
+		ch <- m.Desc()
142
+	}
143
+}
144
+
145
+// Collect returns the current state of all metrics of the collector.
146
+func (c *goCollector) Collect(ch chan<- Metric) {
147
+	// Collect base non-memory metrics.
148
+	c.base.Collect(ch)
149
+
150
+	// Collect must be thread-safe, so prevent concurrent use of
151
+	// rmSampleBuf. Just read into rmSampleBuf but write all the data
152
+	// we get into our Metrics or MemStats.
153
+	//
154
+	// This lock also ensures that the Metrics we send out are all from
155
+	// the same updates, ensuring their mutual consistency insofar as
156
+	// is guaranteed by the runtime/metrics package.
157
+	//
158
+	// N.B. This locking is heavy-handed, but Collect is expected to be called
159
+	// relatively infrequently. Also the core operation here, metrics.Read,
160
+	// is fast (O(tens of microseconds)) so contention should certainly be
161
+	// low, though channel operations and any allocations may add to that.
162
+	c.mu.Lock()
163
+	defer c.mu.Unlock()
164
+
165
+	// Populate runtime/metrics sample buffer.
166
+	metrics.Read(c.rmSampleBuf)
167
+
168
+	// Update all our metrics from rmSampleBuf.
169
+	for i, sample := range c.rmSampleBuf {
170
+		// N.B. switch on concrete type because it's significantly more efficient
171
+		// than checking for the Counter and Gauge interface implementations. In
172
+		// this case, we control all the types here.
173
+		switch m := c.rmMetrics[i].(type) {
174
+		case *counter:
175
+			// Guard against decreases. This should never happen, but a failure
176
+			// to do so will result in a panic, which is a harsh consequence for
177
+			// a metrics collection bug.
178
+			v0, v1 := m.get(), unwrapScalarRMValue(sample.Value)
179
+			if v1 > v0 {
180
+				m.Add(unwrapScalarRMValue(sample.Value) - m.get())
181
+			}
182
+			m.Collect(ch)
183
+		case *gauge:
184
+			m.Set(unwrapScalarRMValue(sample.Value))
185
+			m.Collect(ch)
186
+		case *batchHistogram:
187
+			m.update(sample.Value.Float64Histogram(), c.exactSumFor(sample.Name))
188
+			m.Collect(ch)
189
+		default:
190
+			panic("unexpected metric type")
191
+		}
192
+	}
193
+	// ms is a dummy MemStats that we populate ourselves so that we can
194
+	// populate the old metrics from it.
195
+	var ms runtime.MemStats
196
+	memStatsFromRM(&ms, c.rmSampleMap)
197
+	for _, i := range c.msMetrics {
198
+		ch <- MustNewConstMetric(i.desc, i.valType, i.eval(&ms))
199
+	}
200
+}
201
+
202
+// unwrapScalarRMValue unwraps a runtime/metrics value that is assumed
203
+// to be scalar and returns the equivalent float64 value. Panics if the
204
+// value is not scalar.
205
+func unwrapScalarRMValue(v metrics.Value) float64 {
206
+	switch v.Kind() {
207
+	case metrics.KindUint64:
208
+		return float64(v.Uint64())
209
+	case metrics.KindFloat64:
210
+		return v.Float64()
211
+	case metrics.KindBad:
212
+		// Unsupported metric.
213
+		//
214
+		// This should never happen because we always populate our metric
215
+		// set from the runtime/metrics package.
216
+		panic("unexpected unsupported metric")
217
+	default:
218
+		// Unsupported metric kind.
219
+		//
220
+		// This should never happen because we check for this during initialization
221
+		// and flag and filter metrics whose kinds we don't understand.
222
+		panic("unexpected unsupported metric kind")
223
+	}
224
+}
225
+
226
+var rmExactSumMap = map[string]string{
227
+	"/gc/heap/allocs-by-size:bytes": "/gc/heap/allocs:bytes",
228
+	"/gc/heap/frees-by-size:bytes":  "/gc/heap/frees:bytes",
229
+}
230
+
231
+// exactSumFor takes a runtime/metrics metric name (that is assumed to
232
+// be of kind KindFloat64Histogram) and returns its exact sum and whether
233
+// its exact sum exists.
234
+//
235
+// The runtime/metrics API for histograms doesn't currently expose exact
236
+// sums, but some of the other metrics are in fact exact sums of histograms.
237
+func (c *goCollector) exactSumFor(rmName string) float64 {
238
+	sumName, ok := rmExactSumMap[rmName]
239
+	if !ok {
240
+		return 0
241
+	}
242
+	s, ok := c.rmSampleMap[sumName]
243
+	if !ok {
244
+		return 0
245
+	}
246
+	return unwrapScalarRMValue(s.Value)
247
+}
248
+
249
+func memStatsFromRM(ms *runtime.MemStats, rm map[string]*metrics.Sample) {
250
+	lookupOrZero := func(name string) uint64 {
251
+		if s, ok := rm[name]; ok {
252
+			return s.Value.Uint64()
253
+		}
254
+		return 0
255
+	}
256
+
257
+	// Currently, MemStats adds tiny alloc count to both Mallocs AND Frees.
258
+	// The reason for this is because MemStats couldn't be extended at the time
259
+	// but there was a desire to have Mallocs at least be a little more representative,
260
+	// while having Mallocs - Frees still represent a live object count.
261
+	// Unfortunately, MemStats doesn't actually export a large allocation count,
262
+	// so it's impossible to pull this number out directly.
263
+	tinyAllocs := lookupOrZero("/gc/heap/tiny/allocs:objects")
264
+	ms.Mallocs = lookupOrZero("/gc/heap/allocs:objects") + tinyAllocs
265
+	ms.Frees = lookupOrZero("/gc/heap/frees:objects") + tinyAllocs
266
+
267
+	ms.TotalAlloc = lookupOrZero("/gc/heap/allocs:bytes")
268
+	ms.Sys = lookupOrZero("/memory/classes/total:bytes")
269
+	ms.Lookups = 0 // Already always zero.
270
+	ms.HeapAlloc = lookupOrZero("/memory/classes/heap/objects:bytes")
271
+	ms.Alloc = ms.HeapAlloc
272
+	ms.HeapInuse = ms.HeapAlloc + lookupOrZero("/memory/classes/heap/unused:bytes")
273
+	ms.HeapReleased = lookupOrZero("/memory/classes/heap/released:bytes")
274
+	ms.HeapIdle = ms.HeapReleased + lookupOrZero("/memory/classes/heap/free:bytes")
275
+	ms.HeapSys = ms.HeapInuse + ms.HeapIdle
276
+	ms.HeapObjects = lookupOrZero("/gc/heap/objects:objects")
277
+	ms.StackInuse = lookupOrZero("/memory/classes/heap/stacks:bytes")
278
+	ms.StackSys = ms.StackInuse + lookupOrZero("/memory/classes/os-stacks:bytes")
279
+	ms.MSpanInuse = lookupOrZero("/memory/classes/metadata/mspan/inuse:bytes")
280
+	ms.MSpanSys = ms.MSpanInuse + lookupOrZero("/memory/classes/metadata/mspan/free:bytes")
281
+	ms.MCacheInuse = lookupOrZero("/memory/classes/metadata/mcache/inuse:bytes")
282
+	ms.MCacheSys = ms.MCacheInuse + lookupOrZero("/memory/classes/metadata/mcache/free:bytes")
283
+	ms.BuckHashSys = lookupOrZero("/memory/classes/profiling/buckets:bytes")
284
+	ms.GCSys = lookupOrZero("/memory/classes/metadata/other:bytes")
285
+	ms.OtherSys = lookupOrZero("/memory/classes/other:bytes")
286
+	ms.NextGC = lookupOrZero("/gc/heap/goal:bytes")
287
+
288
+	// N.B. LastGC is omitted because runtime.GCStats already has this.
289
+	// See https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034
290
+	// for more details.
291
+	ms.LastGC = 0
292
+
293
+	// N.B. GCCPUFraction is intentionally omitted. This metric is not useful,
294
+	// and often misleading due to the fact that it's an average over the lifetime
295
+	// of the process.
296
+	// See https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034
297
+	// for more details.
298
+	ms.GCCPUFraction = 0
299
+}
300
+
301
+// batchHistogram is a mutable histogram that is updated
302
+// in batches.
303
+type batchHistogram struct {
304
+	selfCollector
305
+
306
+	// Static fields updated only once.
307
+	desc   *Desc
308
+	hasSum bool
309
+
310
+	// Because this histogram operates in batches, it just uses a
311
+	// single mutex for everything. updates are always serialized
312
+	// but Write calls may operate concurrently with updates.
313
+	// Contention between these two sources should be rare.
314
+	mu      sync.Mutex
315
+	buckets []float64 // Inclusive lower bounds, like runtime/metrics.
316
+	counts  []uint64
317
+	sum     float64 // Used if hasSum is true.
318
+}
319
+
320
+// newBatchHistogram creates a new batch histogram value with the given
321
+// Desc, buckets, and whether or not it has an exact sum available.
322
+//
323
+// buckets must always be from the runtime/metrics package, following
324
+// the same conventions.
325
+func newBatchHistogram(desc *Desc, buckets []float64, hasSum bool) *batchHistogram {
326
+	h := &batchHistogram{
327
+		desc:    desc,
328
+		buckets: buckets,
329
+		// Because buckets follows runtime/metrics conventions, there's
330
+		// 1 more value in the buckets list than there are buckets represented,
331
+		// because in runtime/metrics, the bucket values represent *boundaries*,
332
+		// and non-Inf boundaries are inclusive lower bounds for that bucket.
333
+		counts: make([]uint64, len(buckets)-1),
334
+		hasSum: hasSum,
335
+	}
336
+	h.init(h)
337
+	return h
338
+}
339
+
340
+// update updates the batchHistogram from a runtime/metrics histogram.
341
+//
342
+// sum must be provided if the batchHistogram was created to have an exact sum.
343
+// h.buckets must be a strict subset of his.Buckets.
344
+func (h *batchHistogram) update(his *metrics.Float64Histogram, sum float64) {
345
+	counts, buckets := his.Counts, his.Buckets
346
+
347
+	h.mu.Lock()
348
+	defer h.mu.Unlock()
349
+
350
+	// Clear buckets.
351
+	for i := range h.counts {
352
+		h.counts[i] = 0
353
+	}
354
+	// Copy and reduce buckets.
355
+	var j int
356
+	for i, count := range counts {
357
+		h.counts[j] += count
358
+		if buckets[i+1] == h.buckets[j+1] {
359
+			j++
360
+		}
361
+	}
362
+	if h.hasSum {
363
+		h.sum = sum
364
+	}
365
+}
366
+
367
+func (h *batchHistogram) Desc() *Desc {
368
+	return h.desc
369
+}
370
+
371
+func (h *batchHistogram) Write(out *dto.Metric) error {
372
+	h.mu.Lock()
373
+	defer h.mu.Unlock()
374
+
375
+	sum := float64(0)
376
+	if h.hasSum {
377
+		sum = h.sum
378
+	}
379
+	dtoBuckets := make([]*dto.Bucket, 0, len(h.counts))
380
+	totalCount := uint64(0)
381
+	for i, count := range h.counts {
382
+		totalCount += count
383
+		if !h.hasSum {
384
+			// N.B. This computed sum is an underestimate.
385
+			sum += h.buckets[i] * float64(count)
386
+		}
387
+
388
+		// Skip the +Inf bucket, but only for the bucket list.
389
+		// It must still count for sum and totalCount.
390
+		if math.IsInf(h.buckets[i+1], 1) {
391
+			break
392
+		}
393
+		// Float64Histogram's upper bound is exclusive, so make it inclusive
394
+		// by obtaining the next float64 value down, in order.
395
+		upperBound := math.Nextafter(h.buckets[i+1], h.buckets[i])
396
+		dtoBuckets = append(dtoBuckets, &dto.Bucket{
397
+			CumulativeCount: proto.Uint64(totalCount),
398
+			UpperBound:      proto.Float64(upperBound),
399
+		})
400
+	}
401
+	out.Histogram = &dto.Histogram{
402
+		Bucket:      dtoBuckets,
403
+		SampleCount: proto.Uint64(totalCount),
404
+		SampleSum:   proto.Float64(sum),
405
+	}
406
+	return nil
407
+}
... ...
@@ -22,6 +22,7 @@ import (
22 22
 	"sync/atomic"
23 23
 	"time"
24 24
 
25
+	//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
25 26
 	"github.com/golang/protobuf/proto"
26 27
 
27 28
 	dto "github.com/prometheus/client_model/go"
... ...
@@ -46,7 +47,12 @@ type Histogram interface {
46 46
 	Metric
47 47
 	Collector
48 48
 
49
-	// Observe adds a single observation to the histogram.
49
+	// Observe adds a single observation to the histogram. Observations are
50
+	// usually positive or zero. Negative observations are accepted but
51
+	// prevent current versions of Prometheus from properly detecting
52
+	// counter resets in the sum of observations. See
53
+	// https://prometheus.io/docs/practices/histograms/#count-and-sum-of-observations
54
+	// for details.
50 55
 	Observe(float64)
51 56
 }
52 57
 
... ...
@@ -110,6 +116,34 @@ func ExponentialBuckets(start, factor float64, count int) []float64 {
110 110
 	return buckets
111 111
 }
112 112
 
113
+// ExponentialBucketsRange creates 'count' buckets, where the lowest bucket is
114
+// 'min' and the highest bucket is 'max'. The final +Inf bucket is not counted
115
+// and not included in the returned slice. The returned slice is meant to be
116
+// used for the Buckets field of HistogramOpts.
117
+//
118
+// The function panics if 'count' is 0 or negative, if 'min' is 0 or negative.
119
+func ExponentialBucketsRange(min, max float64, count int) []float64 {
120
+	if count < 1 {
121
+		panic("ExponentialBucketsRange count needs a positive count")
122
+	}
123
+	if min <= 0 {
124
+		panic("ExponentialBucketsRange min needs to be greater than 0")
125
+	}
126
+
127
+	// Formula for exponential buckets.
128
+	// max = min*growthFactor^(bucketCount-1)
129
+
130
+	// We know max/min and highest bucket. Solve for growthFactor.
131
+	growthFactor := math.Pow(max/min, 1.0/float64(count-1))
132
+
133
+	// Now that we know growthFactor, solve for each bucket.
134
+	buckets := make([]float64, count)
135
+	for i := 1; i <= count; i++ {
136
+		buckets[i-1] = min * math.Pow(growthFactor, float64(i-1))
137
+	}
138
+	return buckets
139
+}
140
+
113 141
 // HistogramOpts bundles the options for creating a Histogram metric. It is
114 142
 // mandatory to set Name to a non-empty string. All other fields are optional
115 143
 // and can safely be left at their zero value, although it is strongly
... ...
@@ -191,7 +225,7 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
191 191
 	h := &histogram{
192 192
 		desc:        desc,
193 193
 		upperBounds: opts.Buckets,
194
-		labelPairs:  makeLabelPairs(desc, labelValues),
194
+		labelPairs:  MakeLabelPairs(desc, labelValues),
195 195
 		counts:      [2]*histogramCounts{{}, {}},
196 196
 		now:         time.Now,
197 197
 	}
... ...
@@ -408,7 +442,7 @@ func (h *histogram) updateExemplar(v float64, bucket int, l Labels) {
408 408
 // (e.g. HTTP request latencies, partitioned by status code and method). Create
409 409
 // instances with NewHistogramVec.
410 410
 type HistogramVec struct {
411
-	*metricVec
411
+	*MetricVec
412 412
 }
413 413
 
414 414
 // NewHistogramVec creates a new HistogramVec based on the provided HistogramOpts and
... ...
@@ -421,14 +455,14 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
421 421
 		opts.ConstLabels,
422 422
 	)
423 423
 	return &HistogramVec{
424
-		metricVec: newMetricVec(desc, func(lvs ...string) Metric {
424
+		MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
425 425
 			return newHistogram(desc, opts, lvs...)
426 426
 		}),
427 427
 	}
428 428
 }
429 429
 
430 430
 // GetMetricWithLabelValues returns the Histogram for the given slice of label
431
-// values (same order as the VariableLabels in Desc). If that combination of
431
+// values (same order as the variable labels in Desc). If that combination of
432 432
 // label values is accessed for the first time, a new Histogram is created.
433 433
 //
434 434
 // It is possible to call this method without using the returned Histogram to only
... ...
@@ -443,7 +477,7 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
443 443
 // example.
444 444
 //
445 445
 // An error is returned if the number of label values is not the same as the
446
-// number of VariableLabels in Desc (minus any curried labels).
446
+// number of variable labels in Desc (minus any curried labels).
447 447
 //
448 448
 // Note that for more than one label value, this method is prone to mistakes
449 449
 // caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
... ...
@@ -452,7 +486,7 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
452 452
 // with a performance overhead (for creating and processing the Labels map).
453 453
 // See also the GaugeVec example.
454 454
 func (v *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
455
-	metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
455
+	metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
456 456
 	if metric != nil {
457 457
 		return metric.(Observer), err
458 458
 	}
... ...
@@ -460,19 +494,19 @@ func (v *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Observer, error)
460 460
 }
461 461
 
462 462
 // GetMetricWith returns the Histogram for the given Labels map (the label names
463
-// must match those of the VariableLabels in Desc). If that label map is
463
+// must match those of the variable labels in Desc). If that label map is
464 464
 // accessed for the first time, a new Histogram is created. Implications of
465 465
 // creating a Histogram without using it and keeping the Histogram for later use
466 466
 // are the same as for GetMetricWithLabelValues.
467 467
 //
468 468
 // An error is returned if the number and names of the Labels are inconsistent
469
-// with those of the VariableLabels in Desc (minus any curried labels).
469
+// with those of the variable labels in Desc (minus any curried labels).
470 470
 //
471 471
 // This method is used for the same purpose as
472 472
 // GetMetricWithLabelValues(...string). See there for pros and cons of the two
473 473
 // methods.
474 474
 func (v *HistogramVec) GetMetricWith(labels Labels) (Observer, error) {
475
-	metric, err := v.metricVec.getMetricWith(labels)
475
+	metric, err := v.MetricVec.GetMetricWith(labels)
476 476
 	if metric != nil {
477 477
 		return metric.(Observer), err
478 478
 	}
... ...
@@ -516,7 +550,7 @@ func (v *HistogramVec) With(labels Labels) Observer {
516 516
 // registered with a given registry (usually the uncurried version). The Reset
517 517
 // method deletes all metrics, even if called on a curried vector.
518 518
 func (v *HistogramVec) CurryWith(labels Labels) (ObserverVec, error) {
519
-	vec, err := v.curryWith(labels)
519
+	vec, err := v.MetricVec.CurryWith(labels)
520 520
 	if vec != nil {
521 521
 		return &HistogramVec{vec}, err
522 522
 	}
... ...
@@ -601,12 +635,12 @@ func NewConstHistogram(
601 601
 		count:      count,
602 602
 		sum:        sum,
603 603
 		buckets:    buckets,
604
-		labelPairs: makeLabelPairs(desc, labelValues),
604
+		labelPairs: MakeLabelPairs(desc, labelValues),
605 605
 	}, nil
606 606
 }
607 607
 
608 608
 // MustNewConstHistogram is a version of NewConstHistogram that panics where
609
-// NewConstMetric would have returned an error.
609
+// NewConstHistogram would have returned an error.
610 610
 func MustNewConstHistogram(
611 611
 	desc *Desc,
612 612
 	count uint64,
613 613
new file mode 100644
... ...
@@ -0,0 +1,142 @@
0
+// Copyright 2021 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+//go:build go1.17
14
+// +build go1.17
15
+
16
+package internal
17
+
18
+import (
19
+	"math"
20
+	"path"
21
+	"runtime/metrics"
22
+	"strings"
23
+
24
+	"github.com/prometheus/common/model"
25
+)
26
+
27
+// RuntimeMetricsToProm produces a Prometheus metric name from a runtime/metrics
28
+// metric description and validates whether the metric is suitable for integration
29
+// with Prometheus.
30
+//
31
+// Returns false if a name could not be produced, or if Prometheus does not understand
32
+// the runtime/metrics Kind.
33
+//
34
+// Note that the main reason a name couldn't be produced is if the runtime/metrics
35
+// package exports a name with characters outside the valid Prometheus metric name
36
+// character set. This is theoretically possible, but should never happen in practice.
37
+// Still, don't rely on it.
38
+func RuntimeMetricsToProm(d *metrics.Description) (string, string, string, bool) {
39
+	namespace := "go"
40
+
41
+	comp := strings.SplitN(d.Name, ":", 2)
42
+	key := comp[0]
43
+	unit := comp[1]
44
+
45
+	// The last path element in the key is the name,
46
+	// the rest is the subsystem.
47
+	subsystem := path.Dir(key[1:] /* remove leading / */)
48
+	name := path.Base(key)
49
+
50
+	// subsystem is translated by replacing all / and - with _.
51
+	subsystem = strings.ReplaceAll(subsystem, "/", "_")
52
+	subsystem = strings.ReplaceAll(subsystem, "-", "_")
53
+
54
+	// unit is translated assuming that the unit contains no
55
+	// non-ASCII characters.
56
+	unit = strings.ReplaceAll(unit, "-", "_")
57
+	unit = strings.ReplaceAll(unit, "*", "_")
58
+	unit = strings.ReplaceAll(unit, "/", "_per_")
59
+
60
+	// name has - replaced with _ and is concatenated with the unit and
61
+	// other data.
62
+	name = strings.ReplaceAll(name, "-", "_")
63
+	name = name + "_" + unit
64
+	if d.Cumulative {
65
+		name = name + "_total"
66
+	}
67
+
68
+	valid := model.IsValidMetricName(model.LabelValue(namespace + "_" + subsystem + "_" + name))
69
+	switch d.Kind {
70
+	case metrics.KindUint64:
71
+	case metrics.KindFloat64:
72
+	case metrics.KindFloat64Histogram:
73
+	default:
74
+		valid = false
75
+	}
76
+	return namespace, subsystem, name, valid
77
+}
78
+
79
+// RuntimeMetricsBucketsForUnit takes a set of buckets obtained for a runtime/metrics histogram
80
+// type (so, lower-bound inclusive) and a unit from a runtime/metrics name, and produces
81
+// a reduced set of buckets. This function always removes any -Inf bucket as it's represented
82
+// as the bottom-most upper-bound inclusive bucket in Prometheus.
83
+func RuntimeMetricsBucketsForUnit(buckets []float64, unit string) []float64 {
84
+	switch unit {
85
+	case "bytes":
86
+		// Rebucket as powers of 2.
87
+		return rebucketExp(buckets, 2)
88
+	case "seconds":
89
+		// Rebucket as powers of 10 and then merge all buckets greater
90
+		// than 1 second into the +Inf bucket.
91
+		b := rebucketExp(buckets, 10)
92
+		for i := range b {
93
+			if b[i] <= 1 {
94
+				continue
95
+			}
96
+			b[i] = math.Inf(1)
97
+			b = b[:i+1]
98
+			break
99
+		}
100
+		return b
101
+	}
102
+	return buckets
103
+}
104
+
105
+// rebucketExp takes a list of bucket boundaries (lower bound inclusive) and
106
+// downsamples the buckets to those a multiple of base apart. The end result
107
+// is a roughly exponential (in many cases, perfectly exponential) bucketing
108
+// scheme.
109
+func rebucketExp(buckets []float64, base float64) []float64 {
110
+	bucket := buckets[0]
111
+	var newBuckets []float64
112
+	// We may see a -Inf here, in which case, add it and skip it
113
+	// since we risk producing NaNs otherwise.
114
+	//
115
+	// We need to preserve -Inf values to maintain runtime/metrics
116
+	// conventions. We'll strip it out later.
117
+	if bucket == math.Inf(-1) {
118
+		newBuckets = append(newBuckets, bucket)
119
+		buckets = buckets[1:]
120
+		bucket = buckets[0]
121
+	}
122
+	// From now on, bucket should always have a non-Inf value because
123
+	// Infs are only ever at the ends of the bucket lists, so
124
+	// arithmetic operations on it are non-NaN.
125
+	for i := 1; i < len(buckets); i++ {
126
+		if bucket >= 0 && buckets[i] < bucket*base {
127
+			// The next bucket we want to include is at least bucket*base.
128
+			continue
129
+		} else if bucket < 0 && buckets[i] < bucket/base {
130
+			// In this case the bucket we're targeting is negative, and since
131
+			// we're ascending through buckets here, we need to divide to get
132
+			// closer to zero exponentially.
133
+			continue
134
+		}
135
+		// The +Inf bucket will always be the last one, and we'll always
136
+		// end up including it here because bucket
137
+		newBuckets = append(newBuckets, bucket)
138
+		bucket = buckets[i]
139
+	}
140
+	return append(newBuckets, bucket)
141
+}
... ...
@@ -17,6 +17,7 @@ import (
17 17
 	"strings"
18 18
 	"time"
19 19
 
20
+	//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
20 21
 	"github.com/golang/protobuf/proto"
21 22
 	"github.com/prometheus/common/model"
22 23
 
... ...
@@ -57,7 +58,7 @@ type Metric interface {
57 57
 }
58 58
 
59 59
 // Opts bundles the options for creating most Metric types. Each metric
60
-// implementation XXX has its own XXXOpts type, but in most cases, it is just be
60
+// implementation XXX has its own XXXOpts type, but in most cases, it is just
61 61
 // an alias of this type (which might change when the requirement arises.)
62 62
 //
63 63
 // It is mandatory to set Name to a non-empty string. All other fields are
... ...
@@ -88,7 +89,7 @@ type Opts struct {
88 88
 	// better covered by target labels set by the scraping Prometheus
89 89
 	// server, or by one specific metric (e.g. a build_info or a
90 90
 	// machine_role metric). See also
91
-	// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels
91
+	// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels
92 92
 	ConstLabels Labels
93 93
 }
94 94
 
... ...
@@ -15,7 +15,11 @@ package prometheus
15 15
 
16 16
 import (
17 17
 	"errors"
18
+	"fmt"
19
+	"io/ioutil"
18 20
 	"os"
21
+	"strconv"
22
+	"strings"
19 23
 )
20 24
 
21 25
 type processCollector struct {
... ...
@@ -50,16 +54,10 @@ type ProcessCollectorOpts struct {
50 50
 	ReportErrors bool
51 51
 }
52 52
 
53
-// NewProcessCollector returns a collector which exports the current state of
54
-// process metrics including CPU, memory and file descriptor usage as well as
55
-// the process start time. The detailed behavior is defined by the provided
56
-// ProcessCollectorOpts. The zero value of ProcessCollectorOpts creates a
57
-// collector for the current process with an empty namespace string and no error
58
-// reporting.
53
+// NewProcessCollector is the obsolete version of collectors.NewProcessCollector.
54
+// See there for documentation.
59 55
 //
60
-// The collector only works on operating systems with a Linux-style proc
61
-// filesystem and on Microsoft Windows. On other operating systems, it will not
62
-// collect any metrics.
56
+// Deprecated: Use collectors.NewProcessCollector instead.
63 57
 func NewProcessCollector(opts ProcessCollectorOpts) Collector {
64 58
 	ns := ""
65 59
 	if len(opts.Namespace) > 0 {
... ...
@@ -149,3 +147,20 @@ func (c *processCollector) reportError(ch chan<- Metric, desc *Desc, err error)
149 149
 	}
150 150
 	ch <- NewInvalidMetric(desc, err)
151 151
 }
152
+
153
+// NewPidFileFn returns a function that retrieves a pid from the specified file.
154
+// It is meant to be used for the PidFn field in ProcessCollectorOpts.
155
+func NewPidFileFn(pidFilePath string) func() (int, error) {
156
+	return func() (int, error) {
157
+		content, err := ioutil.ReadFile(pidFilePath)
158
+		if err != nil {
159
+			return 0, fmt.Errorf("can't read pid file %q: %+v", pidFilePath, err)
160
+		}
161
+		pid, err := strconv.Atoi(strings.TrimSpace(string(content)))
162
+		if err != nil {
163
+			return 0, fmt.Errorf("can't parse pid file %q: %+v", pidFilePath, err)
164
+		}
165
+
166
+		return pid, nil
167
+	}
168
+}
... ...
@@ -11,6 +11,7 @@
11 11
 // See the License for the specific language governing permissions and
12 12
 // limitations under the License.
13 13
 
14
+//go:build !windows
14 15
 // +build !windows
15 16
 
16 17
 package prometheus
... ...
@@ -83,8 +83,7 @@ type readerFromDelegator struct{ *responseWriterDelegator }
83 83
 type pusherDelegator struct{ *responseWriterDelegator }
84 84
 
85 85
 func (d closeNotifierDelegator) CloseNotify() <-chan bool {
86
-	//lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to
87
-	//remove support from client_golang yet.
86
+	//nolint:staticcheck // Ignore SA1019. http.CloseNotifier is deprecated but we keep it here to not break existing users.
88 87
 	return d.ResponseWriter.(http.CloseNotifier).CloseNotify()
89 88
 }
90 89
 func (d flusherDelegator) Flush() {
... ...
@@ -348,8 +347,7 @@ func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) deleg
348 348
 	}
349 349
 
350 350
 	id := 0
351
-	//lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to
352
-	//remove support from client_golang yet.
351
+	//nolint:staticcheck // Ignore SA1019. http.CloseNotifier is deprecated but we keep it here to not break existing users.
353 352
 	if _, ok := w.(http.CloseNotifier); ok {
354 353
 		id += closeNotifier
355 354
 	}
... ...
@@ -99,7 +99,7 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
99 99
 		inFlightSem = make(chan struct{}, opts.MaxRequestsInFlight)
100 100
 	}
101 101
 	if opts.Registry != nil {
102
-		// Initialize all possibilites that can occur below.
102
+		// Initialize all possibilities that can occur below.
103 103
 		errCnt.WithLabelValues("gathering")
104 104
 		errCnt.WithLabelValues("encoding")
105 105
 		if err := opts.Registry.Register(errCnt); err != nil {
... ...
@@ -303,8 +303,12 @@ type Logger interface {
303 303
 // HandlerOpts specifies options how to serve metrics via an http.Handler. The
304 304
 // zero value of HandlerOpts is a reasonable default.
305 305
 type HandlerOpts struct {
306
-	// ErrorLog specifies an optional logger for errors collecting and
307
-	// serving metrics. If nil, errors are not logged at all.
306
+	// ErrorLog specifies an optional Logger for errors collecting and
307
+	// serving metrics. If nil, errors are not logged at all. Note that the
308
+	// type of a reported error is often prometheus.MultiError, which
309
+	// formats into a multi-line error string. If you want to avoid the
310
+	// latter, create a Logger implementation that detects a
311
+	// prometheus.MultiError and formats the contained errors into one line.
308 312
 	ErrorLog Logger
309 313
 	// ErrorHandling defines how errors are handled. Note that errors are
310 314
 	// logged regardless of the configured ErrorHandling provided ErrorLog
... ...
@@ -49,7 +49,10 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp
49 49
 // http.RoundTripper to observe the request result with the provided CounterVec.
50 50
 // The CounterVec must have zero, one, or two non-const non-curried labels. For
51 51
 // those, the only allowed label names are "code" and "method". The function
52
-// panics otherwise. Partitioning of the CounterVec happens by HTTP status code
52
+// panics otherwise. For the "method" label a predefined default label value set
53
+// is used to filter given values. Values besides predefined values will count
54
+// as `unknown` method.`WithExtraMethods` can be used to add more
55
+// methods to the set. Partitioning of the CounterVec happens by HTTP status code
53 56
 // and/or HTTP method if the respective instance label names are present in the
54 57
 // CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
55 58
 //
... ...
@@ -57,13 +60,18 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp
57 57
 // is not incremented.
58 58
 //
59 59
 // See the example for ExampleInstrumentRoundTripperDuration for example usage.
60
-func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper) RoundTripperFunc {
60
+func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
61
+	rtOpts := &option{}
62
+	for _, o := range opts {
63
+		o(rtOpts)
64
+	}
65
+
61 66
 	code, method := checkLabels(counter)
62 67
 
63 68
 	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
64 69
 		resp, err := next.RoundTrip(r)
65 70
 		if err == nil {
66
-			counter.With(labels(code, method, r.Method, resp.StatusCode)).Inc()
71
+			counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Inc()
67 72
 		}
68 73
 		return resp, err
69 74
 	})
... ...
@@ -73,7 +81,10 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
73 73
 // http.RoundTripper to observe the request duration with the provided
74 74
 // ObserverVec.  The ObserverVec must have zero, one, or two non-const
75 75
 // non-curried labels. For those, the only allowed label names are "code" and
76
-// "method". The function panics otherwise. The Observe method of the Observer
76
+// "method". The function panics otherwise. For the "method" label a predefined
77
+// default label value set is used to filter given values. Values besides
78
+// predefined values will count as `unknown` method. `WithExtraMethods`
79
+// can be used to add more methods to the set. The Observe method of the Observer
77 80
 // in the ObserverVec is called with the request duration in
78 81
 // seconds. Partitioning happens by HTTP status code and/or HTTP method if the
79 82
 // respective instance label names are present in the ObserverVec. For
... ...
@@ -85,14 +96,19 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
85 85
 //
86 86
 // Note that this method is only guaranteed to never observe negative durations
87 87
 // if used with Go1.9+.
88
-func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper) RoundTripperFunc {
88
+func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
89
+	rtOpts := &option{}
90
+	for _, o := range opts {
91
+		o(rtOpts)
92
+	}
93
+
89 94
 	code, method := checkLabels(obs)
90 95
 
91 96
 	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
92 97
 		start := time.Now()
93 98
 		resp, err := next.RoundTrip(r)
94 99
 		if err == nil {
95
-			obs.With(labels(code, method, r.Method, resp.StatusCode)).Observe(time.Since(start).Seconds())
100
+			obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Observe(time.Since(start).Seconds())
96 101
 		}
97 102
 		return resp, err
98 103
 	})
... ...
@@ -43,14 +43,17 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
43 43
 
44 44
 // InstrumentHandlerDuration is a middleware that wraps the provided
45 45
 // http.Handler to observe the request duration with the provided ObserverVec.
46
-// The ObserverVec must have zero, one, or two non-const non-curried labels. For
47
-// those, the only allowed label names are "code" and "method". The function
48
-// panics otherwise. The Observe method of the Observer in the ObserverVec is
49
-// called with the request duration in seconds. Partitioning happens by HTTP
50
-// status code and/or HTTP method if the respective instance label names are
51
-// present in the ObserverVec. For unpartitioned observations, use an
52
-// ObserverVec with zero labels. Note that partitioning of Histograms is
53
-// expensive and should be used judiciously.
46
+// The ObserverVec must have valid metric and label names and must have zero,
47
+// one, or two non-const non-curried labels. For those, the only allowed label
48
+// names are "code" and "method". The function panics otherwise. For the "method"
49
+// label a predefined default label value set is used to filter given values.
50
+// Values besides predefined values will count as `unknown` method.
51
+//`WithExtraMethods` can be used to add more methods to the set. The Observe
52
+// method of the Observer in the ObserverVec is called with the request duration
53
+// in seconds. Partitioning happens by HTTP status code and/or HTTP method if
54
+// the respective instance label names are present in the ObserverVec. For
55
+// unpartitioned observations, use an ObserverVec with zero labels. Note that
56
+// partitioning of Histograms is expensive and should be used judiciously.
54 57
 //
55 58
 // If the wrapped Handler does not set a status code, a status code of 200 is assumed.
56 59
 //
... ...
@@ -58,7 +61,12 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
58 58
 //
59 59
 // Note that this method is only guaranteed to never observe negative durations
60 60
 // if used with Go1.9+.
61
-func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
61
+func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
62
+	mwOpts := &option{}
63
+	for _, o := range opts {
64
+		o(mwOpts)
65
+	}
66
+
62 67
 	code, method := checkLabels(obs)
63 68
 
64 69
 	if code {
... ...
@@ -67,57 +75,70 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
67 67
 			d := newDelegator(w, nil)
68 68
 			next.ServeHTTP(d, r)
69 69
 
70
-			obs.With(labels(code, method, r.Method, d.Status())).Observe(time.Since(now).Seconds())
70
+			obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
71 71
 		})
72 72
 	}
73 73
 
74 74
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
75 75
 		now := time.Now()
76 76
 		next.ServeHTTP(w, r)
77
-		obs.With(labels(code, method, r.Method, 0)).Observe(time.Since(now).Seconds())
77
+		obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
78 78
 	})
79 79
 }
80 80
 
81 81
 // InstrumentHandlerCounter is a middleware that wraps the provided http.Handler
82
-// to observe the request result with the provided CounterVec.  The CounterVec
83
-// must have zero, one, or two non-const non-curried labels. For those, the only
84
-// allowed label names are "code" and "method". The function panics
85
-// otherwise. Partitioning of the CounterVec happens by HTTP status code and/or
86
-// HTTP method if the respective instance label names are present in the
87
-// CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
82
+// to observe the request result with the provided CounterVec. The CounterVec
83
+// must have valid metric and label names and must have zero, one, or two
84
+// non-const non-curried labels. For those, the only allowed label names are
85
+// "code" and "method". The function panics otherwise. For the "method"
86
+// label a predefined default label value set is used to filter given values.
87
+// Values besides predefined values will count as `unknown` method.
88
+// `WithExtraMethods` can be used to add more methods to the set. Partitioning of the
89
+// CounterVec happens by HTTP status code and/or HTTP method if the respective
90
+// instance label names are present in the CounterVec. For unpartitioned
91
+// counting, use a CounterVec with zero labels.
88 92
 //
89 93
 // If the wrapped Handler does not set a status code, a status code of 200 is assumed.
90 94
 //
91 95
 // If the wrapped Handler panics, the Counter is not incremented.
92 96
 //
93 97
 // See the example for InstrumentHandlerDuration for example usage.
94
-func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler) http.HandlerFunc {
98
+func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler, opts ...Option) http.HandlerFunc {
99
+	mwOpts := &option{}
100
+	for _, o := range opts {
101
+		o(mwOpts)
102
+	}
103
+
95 104
 	code, method := checkLabels(counter)
96 105
 
97 106
 	if code {
98 107
 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
99 108
 			d := newDelegator(w, nil)
100 109
 			next.ServeHTTP(d, r)
101
-			counter.With(labels(code, method, r.Method, d.Status())).Inc()
110
+			counter.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Inc()
102 111
 		})
103 112
 	}
104 113
 
105 114
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
106 115
 		next.ServeHTTP(w, r)
107
-		counter.With(labels(code, method, r.Method, 0)).Inc()
116
+		counter.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Inc()
108 117
 	})
109 118
 }
110 119
 
111 120
 // InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided
112 121
 // http.Handler to observe with the provided ObserverVec the request duration
113
-// until the response headers are written. The ObserverVec must have zero, one,
114
-// or two non-const non-curried labels. For those, the only allowed label names
115
-// are "code" and "method". The function panics otherwise. The Observe method of
116
-// the Observer in the ObserverVec is called with the request duration in
117
-// seconds. Partitioning happens by HTTP status code and/or HTTP method if the
118
-// respective instance label names are present in the ObserverVec. For
119
-// unpartitioned observations, use an ObserverVec with zero labels. Note that
120
-// partitioning of Histograms is expensive and should be used judiciously.
122
+// until the response headers are written. The ObserverVec must have valid
123
+// metric and label names and must have zero, one, or two non-const non-curried
124
+// labels. For those, the only allowed label names are "code" and "method". The
125
+// function panics otherwise. For the "method" label a predefined default label
126
+// value set is used to filter given values. Values besides predefined values
127
+// will count as `unknown` method.`WithExtraMethods` can be used to add more
128
+// methods to the set. The Observe method of the Observer in the
129
+// ObserverVec is called with the request duration in seconds. Partitioning
130
+// happens by HTTP status code and/or HTTP method if the respective instance
131
+// label names are present in the ObserverVec. For unpartitioned observations,
132
+// use an ObserverVec with zero labels. Note that partitioning of Histograms is
133
+// expensive and should be used judiciously.
121 134
 //
122 135
 // If the wrapped Handler panics before calling WriteHeader, no value is
123 136
 // reported.
... ...
@@ -126,35 +147,48 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
126 126
 // if used with Go1.9+.
127 127
 //
128 128
 // See the example for InstrumentHandlerDuration for example usage.
129
-func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
129
+func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
130
+	mwOpts := &option{}
131
+	for _, o := range opts {
132
+		o(mwOpts)
133
+	}
134
+
130 135
 	code, method := checkLabels(obs)
131 136
 
132 137
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
133 138
 		now := time.Now()
134 139
 		d := newDelegator(w, func(status int) {
135
-			obs.With(labels(code, method, r.Method, status)).Observe(time.Since(now).Seconds())
140
+			obs.With(labels(code, method, r.Method, status, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
136 141
 		})
137 142
 		next.ServeHTTP(d, r)
138 143
 	})
139 144
 }
140 145
 
141 146
 // InstrumentHandlerRequestSize is a middleware that wraps the provided
142
-// http.Handler to observe the request size with the provided ObserverVec.  The
143
-// ObserverVec must have zero, one, or two non-const non-curried labels. For
144
-// those, the only allowed label names are "code" and "method". The function
145
-// panics otherwise. The Observe method of the Observer in the ObserverVec is
146
-// called with the request size in bytes. Partitioning happens by HTTP status
147
-// code and/or HTTP method if the respective instance label names are present in
148
-// the ObserverVec. For unpartitioned observations, use an ObserverVec with zero
149
-// labels. Note that partitioning of Histograms is expensive and should be used
150
-// judiciously.
147
+// http.Handler to observe the request size with the provided ObserverVec. The
148
+// ObserverVec must have valid metric and label names and must have zero, one,
149
+// or two non-const non-curried labels. For those, the only allowed label names
150
+// are "code" and "method". The function panics otherwise. For the "method"
151
+// label a predefined default label value set is used to filter given values.
152
+// Values besides predefined values will count as `unknown` method.
153
+// `WithExtraMethods` can be used to add more methods to the set. The Observe
154
+// method of the Observer in the ObserverVec is called with the request size in
155
+// bytes. Partitioning happens by HTTP status code and/or HTTP method if the
156
+// respective instance label names are present in the ObserverVec. For
157
+// unpartitioned observations, use an ObserverVec with zero labels. Note that
158
+// partitioning of Histograms is expensive and should be used judiciously.
151 159
 //
152 160
 // If the wrapped Handler does not set a status code, a status code of 200 is assumed.
153 161
 //
154 162
 // If the wrapped Handler panics, no values are reported.
155 163
 //
156 164
 // See the example for InstrumentHandlerDuration for example usage.
157
-func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
165
+func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
166
+	mwOpts := &option{}
167
+	for _, o := range opts {
168
+		o(mwOpts)
169
+	}
170
+
158 171
 	code, method := checkLabels(obs)
159 172
 
160 173
 	if code {
... ...
@@ -162,42 +196,56 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
162 162
 			d := newDelegator(w, nil)
163 163
 			next.ServeHTTP(d, r)
164 164
 			size := computeApproximateRequestSize(r)
165
-			obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(size))
165
+			obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(size))
166 166
 		})
167 167
 	}
168 168
 
169 169
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
170 170
 		next.ServeHTTP(w, r)
171 171
 		size := computeApproximateRequestSize(r)
172
-		obs.With(labels(code, method, r.Method, 0)).Observe(float64(size))
172
+		obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(float64(size))
173 173
 	})
174 174
 }
175 175
 
176 176
 // InstrumentHandlerResponseSize is a middleware that wraps the provided
177
-// http.Handler to observe the response size with the provided ObserverVec.  The
178
-// ObserverVec must have zero, one, or two non-const non-curried labels. For
179
-// those, the only allowed label names are "code" and "method". The function
180
-// panics otherwise. The Observe method of the Observer in the ObserverVec is
181
-// called with the response size in bytes. Partitioning happens by HTTP status
182
-// code and/or HTTP method if the respective instance label names are present in
183
-// the ObserverVec. For unpartitioned observations, use an ObserverVec with zero
184
-// labels. Note that partitioning of Histograms is expensive and should be used
185
-// judiciously.
177
+// http.Handler to observe the response size with the provided ObserverVec. The
178
+// ObserverVec must have valid metric and label names and must have zero, one,
179
+// or two non-const non-curried labels. For those, the only allowed label names
180
+// are "code" and "method". The function panics otherwise. For the "method"
181
+// label a predefined default label value set is used to filter given values.
182
+// Values besides predefined values will count as `unknown` method.
183
+// `WithExtraMethods` can be used to add more methods to the set. The Observe
184
+// method of the Observer in the ObserverVec is called with the response size in
185
+// bytes. Partitioning happens by HTTP status code and/or HTTP method if the
186
+// respective instance label names are present in the ObserverVec. For
187
+// unpartitioned observations, use an ObserverVec with zero labels. Note that
188
+// partitioning of Histograms is expensive and should be used judiciously.
186 189
 //
187 190
 // If the wrapped Handler does not set a status code, a status code of 200 is assumed.
188 191
 //
189 192
 // If the wrapped Handler panics, no values are reported.
190 193
 //
191 194
 // See the example for InstrumentHandlerDuration for example usage.
192
-func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler) http.Handler {
195
+func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.Handler {
196
+	mwOpts := &option{}
197
+	for _, o := range opts {
198
+		o(mwOpts)
199
+	}
200
+
193 201
 	code, method := checkLabels(obs)
202
+
194 203
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
195 204
 		d := newDelegator(w, nil)
196 205
 		next.ServeHTTP(d, r)
197
-		obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(d.Written()))
206
+		obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(d.Written()))
198 207
 	})
199 208
 }
200 209
 
210
+// checkLabels returns whether the provided Collector has a non-const,
211
+// non-curried label named "code" and/or "method". It panics if the provided
212
+// Collector does not have a Desc or has more than one Desc or its Desc is
213
+// invalid. It also panics if the Collector has any non-const, non-curried
214
+// labels that are not named "code" or "method".
201 215
 func checkLabels(c prometheus.Collector) (code bool, method bool) {
202 216
 	// TODO(beorn7): Remove this hacky way to check for instance labels
203 217
 	// once Descriptors can have their dimensionality queried.
... ...
@@ -225,6 +273,10 @@ func checkLabels(c prometheus.Collector) (code bool, method bool) {
225 225
 
226 226
 	close(descc)
227 227
 
228
+	// Make sure the Collector has a valid Desc by registering it with a
229
+	// temporary registry.
230
+	prometheus.NewRegistry().MustRegister(c)
231
+
228 232
 	// Create a ConstMetric with the Desc. Since we don't know how many
229 233
 	// variable labels there are, try for as long as it needs.
230 234
 	for err := errors.New("dummy"); err != nil; lvs = append(lvs, magicString) {
... ...
@@ -279,7 +331,7 @@ func isLabelCurried(c prometheus.Collector, label string) bool {
279 279
 // unnecessary allocations on each request.
280 280
 var emptyLabels = prometheus.Labels{}
281 281
 
282
-func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
282
+func labels(code, method bool, reqMethod string, status int, extraMethods ...string) prometheus.Labels {
283 283
 	if !(code || method) {
284 284
 		return emptyLabels
285 285
 	}
... ...
@@ -289,7 +341,7 @@ func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
289 289
 		labels["code"] = sanitizeCode(status)
290 290
 	}
291 291
 	if method {
292
-		labels["method"] = sanitizeMethod(reqMethod)
292
+		labels["method"] = sanitizeMethod(reqMethod, extraMethods...)
293 293
 	}
294 294
 
295 295
 	return labels
... ...
@@ -319,7 +371,12 @@ func computeApproximateRequestSize(r *http.Request) int {
319 319
 	return s
320 320
 }
321 321
 
322
-func sanitizeMethod(m string) string {
322
+// If the wrapped http.Handler has a known method, it will be sanitized and returned.
323
+// Otherwise, "unknown" will be returned. The known method list can be extended
324
+// as needed by using extraMethods parameter.
325
+func sanitizeMethod(m string, extraMethods ...string) string {
326
+	// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for
327
+	// the methods chosen as default.
323 328
 	switch m {
324 329
 	case "GET", "get":
325 330
 		return "get"
... ...
@@ -337,15 +394,25 @@ func sanitizeMethod(m string) string {
337 337
 		return "options"
338 338
 	case "NOTIFY", "notify":
339 339
 		return "notify"
340
+	case "TRACE", "trace":
341
+		return "trace"
342
+	case "PATCH", "patch":
343
+		return "patch"
340 344
 	default:
341
-		return strings.ToLower(m)
345
+		for _, method := range extraMethods {
346
+			if strings.EqualFold(m, method) {
347
+				return strings.ToLower(m)
348
+			}
349
+		}
350
+		return "unknown"
342 351
 	}
343 352
 }
344 353
 
345 354
 // If the wrapped http.Handler has not set a status code, i.e. the value is
346
-// currently 0, santizeCode will return 200, for consistency with behavior in
355
+// currently 0, sanitizeCode will return 200, for consistency with behavior in
347 356
 // the stdlib.
348 357
 func sanitizeCode(s int) string {
358
+	// See for accepted codes https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
349 359
 	switch s {
350 360
 	case 100:
351 361
 		return "100"
... ...
@@ -442,6 +509,9 @@ func sanitizeCode(s int) string {
442 442
 		return "511"
443 443
 
444 444
 	default:
445
-		return strconv.Itoa(s)
445
+		if s >= 100 && s <= 599 {
446
+			return strconv.Itoa(s)
447
+		}
448
+		return "unknown"
446 449
 	}
447 450
 }
448 451
new file mode 100644
... ...
@@ -0,0 +1,31 @@
0
+// Copyright 2022 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+package promhttp
14
+
15
+// Option are used to configure a middleware or round tripper..
16
+type Option func(*option)
17
+
18
+type option struct {
19
+	extraMethods []string
20
+}
21
+
22
+// WithExtraMethods adds additional HTTP methods to the list of allowed methods.
23
+// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for the default list.
24
+//
25
+// See the example for ExampleInstrumentHandlerWithExtraMethods for example usage.
26
+func WithExtraMethods(methods ...string) Option {
27
+	return func(o *option) {
28
+		o.extraMethods = methods
29
+	}
30
+}
... ...
@@ -26,6 +26,7 @@ import (
26 26
 	"unicode/utf8"
27 27
 
28 28
 	"github.com/cespare/xxhash/v2"
29
+	//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
29 30
 	"github.com/golang/protobuf/proto"
30 31
 	"github.com/prometheus/common/expfmt"
31 32
 
... ...
@@ -214,6 +215,8 @@ func (err AlreadyRegisteredError) Error() string {
214 214
 // by a Gatherer to report multiple errors during MetricFamily gathering.
215 215
 type MultiError []error
216 216
 
217
+// Error formats the contained errors as a bullet point list, preceded by the
218
+// total number of errors. Note that this results in a multi-line string.
217 219
 func (errs MultiError) Error() string {
218 220
 	if len(errs) == 0 {
219 221
 		return ""
... ...
@@ -23,6 +23,7 @@ import (
23 23
 	"time"
24 24
 
25 25
 	"github.com/beorn7/perks/quantile"
26
+	//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
26 27
 	"github.com/golang/protobuf/proto"
27 28
 
28 29
 	dto "github.com/prometheus/client_model/go"
... ...
@@ -54,7 +55,12 @@ type Summary interface {
54 54
 	Metric
55 55
 	Collector
56 56
 
57
-	// Observe adds a single observation to the summary.
57
+	// Observe adds a single observation to the summary. Observations are
58
+	// usually positive or zero. Negative observations are accepted but
59
+	// prevent current versions of Prometheus from properly detecting
60
+	// counter resets in the sum of observations. See
61
+	// https://prometheus.io/docs/practices/histograms/#count-and-sum-of-observations
62
+	// for details.
58 63
 	Observe(float64)
59 64
 }
60 65
 
... ...
@@ -109,7 +115,7 @@ type SummaryOpts struct {
109 109
 	// better covered by target labels set by the scraping Prometheus
110 110
 	// server, or by one specific metric (e.g. a build_info or a
111 111
 	// machine_role metric). See also
112
-	// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels
112
+	// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels
113 113
 	ConstLabels Labels
114 114
 
115 115
 	// Objectives defines the quantile rank estimates with their respective
... ...
@@ -120,7 +126,9 @@ type SummaryOpts struct {
120 120
 	Objectives map[float64]float64
121 121
 
122 122
 	// MaxAge defines the duration for which an observation stays relevant
123
-	// for the summary. Must be positive. The default value is DefMaxAge.
123
+	// for the summary. Only applies to pre-calculated quantiles, does not
124
+	// apply to _sum and _count. Must be positive. The default value is
125
+	// DefMaxAge.
124 126
 	MaxAge time.Duration
125 127
 
126 128
 	// AgeBuckets is the number of buckets used to exclude observations that
... ...
@@ -207,7 +215,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
207 207
 		// Use the lock-free implementation of a Summary without objectives.
208 208
 		s := &noObjectivesSummary{
209 209
 			desc:       desc,
210
-			labelPairs: makeLabelPairs(desc, labelValues),
210
+			labelPairs: MakeLabelPairs(desc, labelValues),
211 211
 			counts:     [2]*summaryCounts{{}, {}},
212 212
 		}
213 213
 		s.init(s) // Init self-collection.
... ...
@@ -220,7 +228,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
220 220
 		objectives:       opts.Objectives,
221 221
 		sortedObjectives: make([]float64, 0, len(opts.Objectives)),
222 222
 
223
-		labelPairs: makeLabelPairs(desc, labelValues),
223
+		labelPairs: MakeLabelPairs(desc, labelValues),
224 224
 
225 225
 		hotBuf:         make([]float64, 0, opts.BufCap),
226 226
 		coldBuf:        make([]float64, 0, opts.BufCap),
... ...
@@ -512,7 +520,7 @@ func (s quantSort) Less(i, j int) bool {
512 512
 // (e.g. HTTP request latencies, partitioned by status code and method). Create
513 513
 // instances with NewSummaryVec.
514 514
 type SummaryVec struct {
515
-	*metricVec
515
+	*MetricVec
516 516
 }
517 517
 
518 518
 // NewSummaryVec creates a new SummaryVec based on the provided SummaryOpts and
... ...
@@ -534,14 +542,14 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
534 534
 		opts.ConstLabels,
535 535
 	)
536 536
 	return &SummaryVec{
537
-		metricVec: newMetricVec(desc, func(lvs ...string) Metric {
537
+		MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
538 538
 			return newSummary(desc, opts, lvs...)
539 539
 		}),
540 540
 	}
541 541
 }
542 542
 
543 543
 // GetMetricWithLabelValues returns the Summary for the given slice of label
544
-// values (same order as the VariableLabels in Desc). If that combination of
544
+// values (same order as the variable labels in Desc). If that combination of
545 545
 // label values is accessed for the first time, a new Summary is created.
546 546
 //
547 547
 // It is possible to call this method without using the returned Summary to only
... ...
@@ -556,7 +564,7 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
556 556
 // example.
557 557
 //
558 558
 // An error is returned if the number of label values is not the same as the
559
-// number of VariableLabels in Desc (minus any curried labels).
559
+// number of variable labels in Desc (minus any curried labels).
560 560
 //
561 561
 // Note that for more than one label value, this method is prone to mistakes
562 562
 // caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
... ...
@@ -565,7 +573,7 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
565 565
 // with a performance overhead (for creating and processing the Labels map).
566 566
 // See also the GaugeVec example.
567 567
 func (v *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
568
-	metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
568
+	metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
569 569
 	if metric != nil {
570 570
 		return metric.(Observer), err
571 571
 	}
... ...
@@ -573,19 +581,19 @@ func (v *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
573 573
 }
574 574
 
575 575
 // GetMetricWith returns the Summary for the given Labels map (the label names
576
-// must match those of the VariableLabels in Desc). If that label map is
576
+// must match those of the variable labels in Desc). If that label map is
577 577
 // accessed for the first time, a new Summary is created. Implications of
578 578
 // creating a Summary without using it and keeping the Summary for later use are
579 579
 // the same as for GetMetricWithLabelValues.
580 580
 //
581 581
 // An error is returned if the number and names of the Labels are inconsistent
582
-// with those of the VariableLabels in Desc (minus any curried labels).
582
+// with those of the variable labels in Desc (minus any curried labels).
583 583
 //
584 584
 // This method is used for the same purpose as
585 585
 // GetMetricWithLabelValues(...string). See there for pros and cons of the two
586 586
 // methods.
587 587
 func (v *SummaryVec) GetMetricWith(labels Labels) (Observer, error) {
588
-	metric, err := v.metricVec.getMetricWith(labels)
588
+	metric, err := v.MetricVec.GetMetricWith(labels)
589 589
 	if metric != nil {
590 590
 		return metric.(Observer), err
591 591
 	}
... ...
@@ -629,7 +637,7 @@ func (v *SummaryVec) With(labels Labels) Observer {
629 629
 // registered with a given registry (usually the uncurried version). The Reset
630 630
 // method deletes all metrics, even if called on a curried vector.
631 631
 func (v *SummaryVec) CurryWith(labels Labels) (ObserverVec, error) {
632
-	vec, err := v.curryWith(labels)
632
+	vec, err := v.MetricVec.CurryWith(labels)
633 633
 	if vec != nil {
634 634
 		return &SummaryVec{vec}, err
635 635
 	}
... ...
@@ -715,7 +723,7 @@ func NewConstSummary(
715 715
 		count:      count,
716 716
 		sum:        sum,
717 717
 		quantiles:  quantiles,
718
-		labelPairs: makeLabelPairs(desc, labelValues),
718
+		labelPairs: MakeLabelPairs(desc, labelValues),
719 719
 	}, nil
720 720
 }
721 721
 
... ...
@@ -19,8 +19,9 @@ import (
19 19
 	"time"
20 20
 	"unicode/utf8"
21 21
 
22
+	//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
22 23
 	"github.com/golang/protobuf/proto"
23
-	"github.com/golang/protobuf/ptypes"
24
+	"google.golang.org/protobuf/types/known/timestamppb"
24 25
 
25 26
 	dto "github.com/prometheus/client_model/go"
26 27
 )
... ...
@@ -62,7 +63,7 @@ func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *val
62 62
 		desc:       desc,
63 63
 		valType:    valueType,
64 64
 		function:   function,
65
-		labelPairs: makeLabelPairs(desc, nil),
65
+		labelPairs: MakeLabelPairs(desc, nil),
66 66
 	}
67 67
 	result.init(result)
68 68
 	return result
... ...
@@ -94,7 +95,7 @@ func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues
94 94
 		desc:       desc,
95 95
 		valType:    valueType,
96 96
 		val:        value,
97
-		labelPairs: makeLabelPairs(desc, labelValues),
97
+		labelPairs: MakeLabelPairs(desc, labelValues),
98 98
 	}, nil
99 99
 }
100 100
 
... ...
@@ -144,7 +145,14 @@ func populateMetric(
144 144
 	return nil
145 145
 }
146 146
 
147
-func makeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
147
+// MakeLabelPairs is a helper function to create protobuf LabelPairs from the
148
+// variable and constant labels in the provided Desc. The values for the
149
+// variable labels are defined by the labelValues slice, which must be in the
150
+// same order as the corresponding variable labels in the Desc.
151
+//
152
+// This function is only needed for custom Metric implementations. See MetricVec
153
+// example.
154
+func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
148 155
 	totalLen := len(desc.variableLabels) + len(desc.constLabelPairs)
149 156
 	if totalLen == 0 {
150 157
 		// Super fast path.
... ...
@@ -175,8 +183,8 @@ const ExemplarMaxRunes = 64
175 175
 func newExemplar(value float64, ts time.Time, l Labels) (*dto.Exemplar, error) {
176 176
 	e := &dto.Exemplar{}
177 177
 	e.Value = proto.Float64(value)
178
-	tsProto, err := ptypes.TimestampProto(ts)
179
-	if err != nil {
178
+	tsProto := timestamppb.New(ts)
179
+	if err := tsProto.CheckValid(); err != nil {
180 180
 		return nil, err
181 181
 	}
182 182
 	e.Timestamp = tsProto
... ...
@@ -20,12 +20,20 @@ import (
20 20
 	"github.com/prometheus/common/model"
21 21
 )
22 22
 
23
-// metricVec is a Collector to bundle metrics of the same name that differ in
24
-// their label values. metricVec is not used directly (and therefore
25
-// unexported). It is used as a building block for implementations of vectors of
26
-// a given metric type, like GaugeVec, CounterVec, SummaryVec, and HistogramVec.
27
-// It also handles label currying.
28
-type metricVec struct {
23
+// MetricVec is a Collector to bundle metrics of the same name that differ in
24
+// their label values. MetricVec is not used directly but as a building block
25
+// for implementations of vectors of a given metric type, like GaugeVec,
26
+// CounterVec, SummaryVec, and HistogramVec. It is exported so that it can be
27
+// used for custom Metric implementations.
28
+//
29
+// To create a FooVec for custom Metric Foo, embed a pointer to MetricVec in
30
+// FooVec and initialize it with NewMetricVec. Implement wrappers for
31
+// GetMetricWithLabelValues and GetMetricWith that return (Foo, error) rather
32
+// than (Metric, error). Similarly, create a wrapper for CurryWith that returns
33
+// (*FooVec, error) rather than (*MetricVec, error). It is recommended to also
34
+// add the convenience methods WithLabelValues, With, and MustCurryWith, which
35
+// panic instead of returning errors. See also the MetricVec example.
36
+type MetricVec struct {
29 37
 	*metricMap
30 38
 
31 39
 	curry []curriedLabelValue
... ...
@@ -35,9 +43,9 @@ type metricVec struct {
35 35
 	hashAddByte func(h uint64, b byte) uint64
36 36
 }
37 37
 
38
-// newMetricVec returns an initialized metricVec.
39
-func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *metricVec {
40
-	return &metricVec{
38
+// NewMetricVec returns an initialized metricVec.
39
+func NewMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *MetricVec {
40
+	return &MetricVec{
41 41
 		metricMap: &metricMap{
42 42
 			metrics:   map[uint64][]metricWithLabelValues{},
43 43
 			desc:      desc,
... ...
@@ -63,7 +71,7 @@ func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *metricVec {
63 63
 // latter has a much more readable (albeit more verbose) syntax, but it comes
64 64
 // with a performance overhead (for creating and processing the Labels map).
65 65
 // See also the CounterVec example.
66
-func (m *metricVec) DeleteLabelValues(lvs ...string) bool {
66
+func (m *MetricVec) DeleteLabelValues(lvs ...string) bool {
67 67
 	h, err := m.hashLabelValues(lvs)
68 68
 	if err != nil {
69 69
 		return false
... ...
@@ -82,7 +90,7 @@ func (m *metricVec) DeleteLabelValues(lvs ...string) bool {
82 82
 //
83 83
 // This method is used for the same purpose as DeleteLabelValues(...string). See
84 84
 // there for pros and cons of the two methods.
85
-func (m *metricVec) Delete(labels Labels) bool {
85
+func (m *MetricVec) Delete(labels Labels) bool {
86 86
 	h, err := m.hashLabels(labels)
87 87
 	if err != nil {
88 88
 		return false
... ...
@@ -95,15 +103,32 @@ func (m *metricVec) Delete(labels Labels) bool {
95 95
 // show up in GoDoc.
96 96
 
97 97
 // Describe implements Collector.
98
-func (m *metricVec) Describe(ch chan<- *Desc) { m.metricMap.Describe(ch) }
98
+func (m *MetricVec) Describe(ch chan<- *Desc) { m.metricMap.Describe(ch) }
99 99
 
100 100
 // Collect implements Collector.
101
-func (m *metricVec) Collect(ch chan<- Metric) { m.metricMap.Collect(ch) }
101
+func (m *MetricVec) Collect(ch chan<- Metric) { m.metricMap.Collect(ch) }
102 102
 
103 103
 // Reset deletes all metrics in this vector.
104
-func (m *metricVec) Reset() { m.metricMap.Reset() }
105
-
106
-func (m *metricVec) curryWith(labels Labels) (*metricVec, error) {
104
+func (m *MetricVec) Reset() { m.metricMap.Reset() }
105
+
106
+// CurryWith returns a vector curried with the provided labels, i.e. the
107
+// returned vector has those labels pre-set for all labeled operations performed
108
+// on it. The cardinality of the curried vector is reduced accordingly. The
109
+// order of the remaining labels stays the same (just with the curried labels
110
+// taken out of the sequence – which is relevant for the
111
+// (GetMetric)WithLabelValues methods). It is possible to curry a curried
112
+// vector, but only with labels not yet used for currying before.
113
+//
114
+// The metrics contained in the MetricVec are shared between the curried and
115
+// uncurried vectors. They are just accessed differently. Curried and uncurried
116
+// vectors behave identically in terms of collection. Only one must be
117
+// registered with a given registry (usually the uncurried version). The Reset
118
+// method deletes all metrics, even if called on a curried vector.
119
+//
120
+// Note that CurryWith is usually not called directly but through a wrapper
121
+// around MetricVec, implementing a vector for a specific Metric
122
+// implementation, for example GaugeVec.
123
+func (m *MetricVec) CurryWith(labels Labels) (*MetricVec, error) {
107 124
 	var (
108 125
 		newCurry []curriedLabelValue
109 126
 		oldCurry = m.curry
... ...
@@ -128,7 +153,7 @@ func (m *metricVec) curryWith(labels Labels) (*metricVec, error) {
128 128
 		return nil, fmt.Errorf("%d unknown label(s) found during currying", l)
129 129
 	}
130 130
 
131
-	return &metricVec{
131
+	return &MetricVec{
132 132
 		metricMap:   m.metricMap,
133 133
 		curry:       newCurry,
134 134
 		hashAdd:     m.hashAdd,
... ...
@@ -136,7 +161,34 @@ func (m *metricVec) curryWith(labels Labels) (*metricVec, error) {
136 136
 	}, nil
137 137
 }
138 138
 
139
-func (m *metricVec) getMetricWithLabelValues(lvs ...string) (Metric, error) {
139
+// GetMetricWithLabelValues returns the Metric for the given slice of label
140
+// values (same order as the variable labels in Desc). If that combination of
141
+// label values is accessed for the first time, a new Metric is created (by
142
+// calling the newMetric function provided during construction of the
143
+// MetricVec).
144
+//
145
+// It is possible to call this method without using the returned Metric to only
146
+// create the new Metric but leave it in its initial state.
147
+//
148
+// Keeping the Metric for later use is possible (and should be considered if
149
+// performance is critical), but keep in mind that Reset, DeleteLabelValues and
150
+// Delete can be used to delete the Metric from the MetricVec. In that case, the
151
+// Metric will still exist, but it will not be exported anymore, even if a
152
+// Metric with the same label values is created later.
153
+//
154
+// An error is returned if the number of label values is not the same as the
155
+// number of variable labels in Desc (minus any curried labels).
156
+//
157
+// Note that for more than one label value, this method is prone to mistakes
158
+// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
159
+// an alternative to avoid that type of mistake. For higher label numbers, the
160
+// latter has a much more readable (albeit more verbose) syntax, but it comes
161
+// with a performance overhead (for creating and processing the Labels map).
162
+//
163
+// Note that GetMetricWithLabelValues is usually not called directly but through
164
+// a wrapper around MetricVec, implementing a vector for a specific Metric
165
+// implementation, for example GaugeVec.
166
+func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) {
140 167
 	h, err := m.hashLabelValues(lvs)
141 168
 	if err != nil {
142 169
 		return nil, err
... ...
@@ -145,7 +197,23 @@ func (m *metricVec) getMetricWithLabelValues(lvs ...string) (Metric, error) {
145 145
 	return m.metricMap.getOrCreateMetricWithLabelValues(h, lvs, m.curry), nil
146 146
 }
147 147
 
148
-func (m *metricVec) getMetricWith(labels Labels) (Metric, error) {
148
+// GetMetricWith returns the Metric for the given Labels map (the label names
149
+// must match those of the variable labels in Desc). If that label map is
150
+// accessed for the first time, a new Metric is created. Implications of
151
+// creating a Metric without using it and keeping the Metric for later use
152
+// are the same as for GetMetricWithLabelValues.
153
+//
154
+// An error is returned if the number and names of the Labels are inconsistent
155
+// with those of the variable labels in Desc (minus any curried labels).
156
+//
157
+// This method is used for the same purpose as
158
+// GetMetricWithLabelValues(...string). See there for pros and cons of the two
159
+// methods.
160
+//
161
+// Note that GetMetricWith is usually not called directly but through a wrapper
162
+// around MetricVec, implementing a vector for a specific Metric implementation,
163
+// for example GaugeVec.
164
+func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) {
149 165
 	h, err := m.hashLabels(labels)
150 166
 	if err != nil {
151 167
 		return nil, err
... ...
@@ -154,7 +222,7 @@ func (m *metricVec) getMetricWith(labels Labels) (Metric, error) {
154 154
 	return m.metricMap.getOrCreateMetricWithLabels(h, labels, m.curry), nil
155 155
 }
156 156
 
157
-func (m *metricVec) hashLabelValues(vals []string) (uint64, error) {
157
+func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) {
158 158
 	if err := validateLabelValues(vals, len(m.desc.variableLabels)-len(m.curry)); err != nil {
159 159
 		return 0, err
160 160
 	}
... ...
@@ -177,7 +245,7 @@ func (m *metricVec) hashLabelValues(vals []string) (uint64, error) {
177 177
 	return h, nil
178 178
 }
179 179
 
180
-func (m *metricVec) hashLabels(labels Labels) (uint64, error) {
180
+func (m *MetricVec) hashLabels(labels Labels) (uint64, error) {
181 181
 	if err := validateValuesInLabels(labels, len(m.desc.variableLabels)-len(m.curry)); err != nil {
182 182
 		return 0, err
183 183
 	}
... ...
@@ -276,7 +344,9 @@ func (m *metricMap) deleteByHashWithLabelValues(
276 276
 	}
277 277
 
278 278
 	if len(metrics) > 1 {
279
+		old := metrics
279 280
 		m.metrics[h] = append(metrics[:i], metrics[i+1:]...)
281
+		old[len(old)-1] = metricWithLabelValues{}
280 282
 	} else {
281 283
 		delete(m.metrics, h)
282 284
 	}
... ...
@@ -302,7 +372,9 @@ func (m *metricMap) deleteByHashWithLabels(
302 302
 	}
303 303
 
304 304
 	if len(metrics) > 1 {
305
+		old := metrics
305 306
 		m.metrics[h] = append(metrics[:i], metrics[i+1:]...)
307
+		old[len(old)-1] = metricWithLabelValues{}
306 308
 	} else {
307 309
 		delete(m.metrics, h)
308 310
 	}
... ...
@@ -17,6 +17,7 @@ import (
17 17
 	"fmt"
18 18
 	"sort"
19 19
 
20
+	//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
20 21
 	"github.com/golang/protobuf/proto"
21 22
 
22 23
 	dto "github.com/prometheus/client_model/go"
... ...
@@ -27,10 +28,13 @@ import (
27 27
 // registered with the wrapped Registerer in a modified way. The modified
28 28
 // Collector adds the provided Labels to all Metrics it collects (as
29 29
 // ConstLabels). The Metrics collected by the unmodified Collector must not
30
-// duplicate any of those labels.
30
+// duplicate any of those labels. Wrapping a nil value is valid, resulting
31
+// in a no-op Registerer.
31 32
 //
32 33
 // WrapRegistererWith provides a way to add fixed labels to a subset of
33
-// Collectors. It should not be used to add fixed labels to all metrics exposed.
34
+// Collectors. It should not be used to add fixed labels to all metrics
35
+// exposed. See also
36
+// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels
34 37
 //
35 38
 // Conflicts between Collectors registered through the original Registerer with
36 39
 // Collectors registered through the wrapping Registerer will still be
... ...
@@ -50,6 +54,7 @@ func WrapRegistererWith(labels Labels, reg Registerer) Registerer {
50 50
 // Registerer. Collectors registered with the returned Registerer will be
51 51
 // registered with the wrapped Registerer in a modified way. The modified
52 52
 // Collector adds the provided prefix to the name of all Metrics it collects.
53
+// Wrapping a nil value is valid, resulting in a no-op Registerer.
53 54
 //
54 55
 // WrapRegistererWithPrefix is useful to have one place to prefix all metrics of
55 56
 // a sub-system. To make this work, register metrics of the sub-system with the
... ...
@@ -80,6 +85,9 @@ type wrappingRegisterer struct {
80 80
 }
81 81
 
82 82
 func (r *wrappingRegisterer) Register(c Collector) error {
83
+	if r.wrappedRegisterer == nil {
84
+		return nil
85
+	}
83 86
 	return r.wrappedRegisterer.Register(&wrappingCollector{
84 87
 		wrappedCollector: c,
85 88
 		prefix:           r.prefix,
... ...
@@ -88,6 +96,9 @@ func (r *wrappingRegisterer) Register(c Collector) error {
88 88
 }
89 89
 
90 90
 func (r *wrappingRegisterer) MustRegister(cs ...Collector) {
91
+	if r.wrappedRegisterer == nil {
92
+		return
93
+	}
91 94
 	for _, c := range cs {
92 95
 		if err := r.Register(c); err != nil {
93 96
 			panic(err)
... ...
@@ -96,6 +107,9 @@ func (r *wrappingRegisterer) MustRegister(cs ...Collector) {
96 96
 }
97 97
 
98 98
 func (r *wrappingRegisterer) Unregister(c Collector) bool {
99
+	if r.wrappedRegisterer == nil {
100
+		return false
101
+	}
99 102
 	return r.wrappedRegisterer.Unregister(&wrappingCollector{
100 103
 		wrappedCollector: c,
101 104
 		prefix:           r.prefix,
102 105
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+## Prometheus Community Code of Conduct
1
+
2
+Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
... ...
@@ -18,6 +18,8 @@ include Makefile.common
18 18
 	./ttar -C $(dir $*) -x -f $*.ttar
19 19
 	touch $@
20 20
 
21
+fixtures: fixtures/.unpacked
22
+
21 23
 update_fixtures:
22 24
 	rm -vf fixtures/.unpacked
23 25
 	./ttar -c -f fixtures.ttar fixtures/
... ...
@@ -78,12 +78,12 @@ ifneq ($(shell which gotestsum),)
78 78
 endif
79 79
 endif
80 80
 
81
-PROMU_VERSION ?= 0.5.0
81
+PROMU_VERSION ?= 0.12.0
82 82
 PROMU_URL     := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
83 83
 
84 84
 GOLANGCI_LINT :=
85 85
 GOLANGCI_LINT_OPTS ?=
86
-GOLANGCI_LINT_VERSION ?= v1.18.0
86
+GOLANGCI_LINT_VERSION ?= v1.39.0
87 87
 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
88 88
 # windows isn't included here because of the path separator being different.
89 89
 ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
... ...
@@ -118,7 +118,7 @@ endif
118 118
 %: common-% ;
119 119
 
120 120
 .PHONY: common-all
121
-common-all: precheck style check_license lint unused build test
121
+common-all: precheck style check_license lint yamllint unused build test
122 122
 
123 123
 .PHONY: common-style
124 124
 common-style:
... ...
@@ -150,6 +150,17 @@ else
150 150
 	$(GO) get $(GOOPTS) -t ./...
151 151
 endif
152 152
 
153
+.PHONY: update-go-deps
154
+update-go-deps:
155
+	@echo ">> updating Go dependencies"
156
+	@for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \
157
+		$(GO) get $$m; \
158
+	done
159
+	GO111MODULE=$(GO111MODULE) $(GO) mod tidy
160
+ifneq (,$(wildcard vendor))
161
+	GO111MODULE=$(GO111MODULE) $(GO) mod vendor
162
+endif
163
+
153 164
 .PHONY: common-test-short
154 165
 common-test-short: $(GOTEST_DIR)
155 166
 	@echo ">> running short tests"
... ...
@@ -187,6 +198,15 @@ else
187 187
 endif
188 188
 endif
189 189
 
190
+.PHONY: common-yamllint
191
+common-yamllint:
192
+	@echo ">> running yamllint on all YAML files in the repository"
193
+ifeq (, $(shell which yamllint))
194
+	@echo "yamllint not installed so skipping"
195
+else
196
+	yamllint .
197
+endif
198
+
190 199
 # For backward-compatibility.
191 200
 .PHONY: common-staticcheck
192 201
 common-staticcheck: lint
... ...
@@ -234,10 +254,12 @@ common-docker-publish: $(PUBLISH_DOCKER_ARCHS)
234 234
 $(PUBLISH_DOCKER_ARCHS): common-docker-publish-%:
235 235
 	docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)"
236 236
 
237
+DOCKER_MAJOR_VERSION_TAG = $(firstword $(subst ., ,$(shell cat VERSION)))
237 238
 .PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS)
238 239
 common-docker-tag-latest: $(TAG_DOCKER_ARCHS)
239 240
 $(TAG_DOCKER_ARCHS): common-docker-tag-latest-%:
240 241
 	docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"
242
+	docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)"
241 243
 
242 244
 .PHONY: common-docker-manifest
243 245
 common-docker-manifest:
... ...
@@ -6,8 +6,8 @@ metrics from the pseudo-filesystems /proc and /sys.
6 6
 *WARNING*: This package is a work in progress. Its API may still break in
7 7
 backwards-incompatible ways without warnings. Use it at your own risk.
8 8
 
9
-[![GoDoc](https://godoc.org/github.com/prometheus/procfs?status.png)](https://godoc.org/github.com/prometheus/procfs)
10
-[![Build Status](https://travis-ci.org/prometheus/procfs.svg?branch=master)](https://travis-ci.org/prometheus/procfs)
9
+[![Go Reference](https://pkg.go.dev/badge/github.com/prometheus/procfs.svg)](https://pkg.go.dev/github.com/prometheus/procfs)
10
+[![CircleCI](https://circleci.com/gh/prometheus/procfs/tree/master.svg?style=svg)](https://circleci.com/gh/prometheus/procfs/tree/master)
11 11
 [![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/procfs)](https://goreportcard.com/report/github.com/prometheus/procfs)
12 12
 
13 13
 ## Usage
14 14
new file mode 100644
... ...
@@ -0,0 +1,6 @@
0
+# Reporting a security issue
1
+
2
+The Prometheus security policy, including how to report vulnerabilities, can be
3
+found here:
4
+
5
+https://prometheus.io/docs/operating/security/
... ...
@@ -36,7 +36,7 @@ type ARPEntry struct {
36 36
 func (fs FS) GatherARPEntries() ([]ARPEntry, error) {
37 37
 	data, err := ioutil.ReadFile(fs.proc.Path("net/arp"))
38 38
 	if err != nil {
39
-		return nil, fmt.Errorf("error reading arp %s: %s", fs.proc.Path("net/arp"), err)
39
+		return nil, fmt.Errorf("error reading arp %q: %w", fs.proc.Path("net/arp"), err)
40 40
 	}
41 41
 
42 42
 	return parseARPEntries(data)
... ...
@@ -59,7 +59,7 @@ func parseARPEntries(data []byte) ([]ARPEntry, error) {
59 59
 		} else if width == expectedDataWidth {
60 60
 			entry, err := parseARPEntry(columns)
61 61
 			if err != nil {
62
-				return []ARPEntry{}, fmt.Errorf("failed to parse ARP entry: %s", err)
62
+				return []ARPEntry{}, fmt.Errorf("failed to parse ARP entry: %w", err)
63 63
 			}
64 64
 			entries = append(entries, entry)
65 65
 		} else {
... ...
@@ -74,7 +74,7 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
74 74
 		for i := 0; i < arraySize; i++ {
75 75
 			sizes[i], err = strconv.ParseFloat(parts[i+4], 64)
76 76
 			if err != nil {
77
-				return nil, fmt.Errorf("invalid value in buddyinfo: %s", err)
77
+				return nil, fmt.Errorf("invalid value in buddyinfo: %w", err)
78 78
 			}
79 79
 		}
80 80
 
81 81
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+// Copyright 2021 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+package procfs
14
+
15
+import (
16
+	"strings"
17
+
18
+	"github.com/prometheus/procfs/internal/util"
19
+)
20
+
21
+// CmdLine returns the command line of the kernel.
22
+func (fs FS) CmdLine() ([]string, error) {
23
+	data, err := util.ReadFileNoStat(fs.proc.Path("cmdline"))
24
+	if err != nil {
25
+		return nil, err
26
+	}
27
+
28
+	return strings.Fields(string(data)), nil
29
+}
... ...
@@ -11,11 +11,16 @@
11 11
 // See the License for the specific language governing permissions and
12 12
 // limitations under the License.
13 13
 
14
+// +build linux
15
+
14 16
 package procfs
15 17
 
16 18
 import (
17 19
 	"bufio"
18 20
 	"bytes"
21
+	"errors"
22
+	"fmt"
23
+	"regexp"
19 24
 	"strconv"
20 25
 	"strings"
21 26
 
... ...
@@ -52,6 +57,11 @@ type CPUInfo struct {
52 52
 	PowerManagement string
53 53
 }
54 54
 
55
+var (
56
+	cpuinfoClockRegexp          = regexp.MustCompile(`([\d.]+)`)
57
+	cpuinfoS390XProcessorRegexp = regexp.MustCompile(`^processor\s+(\d+):.*`)
58
+)
59
+
55 60
 // CPUInfo returns information about current system CPUs.
56 61
 // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
57 62
 func (fs FS) CPUInfo() ([]CPUInfo, error) {
... ...
@@ -62,14 +72,26 @@ func (fs FS) CPUInfo() ([]CPUInfo, error) {
62 62
 	return parseCPUInfo(data)
63 63
 }
64 64
 
65
-// parseCPUInfo parses data from /proc/cpuinfo
66
-func parseCPUInfo(info []byte) ([]CPUInfo, error) {
67
-	cpuinfo := []CPUInfo{}
68
-	i := -1
65
+func parseCPUInfoX86(info []byte) ([]CPUInfo, error) {
69 66
 	scanner := bufio.NewScanner(bytes.NewReader(info))
67
+
68
+	// find the first "processor" line
69
+	firstLine := firstNonEmptyLine(scanner)
70
+	if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
71
+		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
72
+	}
73
+	field := strings.SplitN(firstLine, ": ", 2)
74
+	v, err := strconv.ParseUint(field[1], 0, 32)
75
+	if err != nil {
76
+		return nil, err
77
+	}
78
+	firstcpu := CPUInfo{Processor: uint(v)}
79
+	cpuinfo := []CPUInfo{firstcpu}
80
+	i := 0
81
+
70 82
 	for scanner.Scan() {
71 83
 		line := scanner.Text()
72
-		if strings.TrimSpace(line) == "" {
84
+		if !strings.Contains(line, ":") {
73 85
 			continue
74 86
 		}
75 87
 		field := strings.SplitN(line, ": ", 2)
... ...
@@ -82,7 +104,7 @@ func parseCPUInfo(info []byte) ([]CPUInfo, error) {
82 82
 				return nil, err
83 83
 			}
84 84
 			cpuinfo[i].Processor = uint(v)
85
-		case "vendor_id":
85
+		case "vendor", "vendor_id":
86 86
 			cpuinfo[i].VendorID = field[1]
87 87
 		case "cpu family":
88 88
 			cpuinfo[i].CPUFamily = field[1]
... ...
@@ -163,5 +185,297 @@ func parseCPUInfo(info []byte) ([]CPUInfo, error) {
163 163
 		}
164 164
 	}
165 165
 	return cpuinfo, nil
166
+}
167
+
168
+func parseCPUInfoARM(info []byte) ([]CPUInfo, error) {
169
+	scanner := bufio.NewScanner(bytes.NewReader(info))
170
+
171
+	firstLine := firstNonEmptyLine(scanner)
172
+	match, _ := regexp.MatchString("^[Pp]rocessor", firstLine)
173
+	if !match || !strings.Contains(firstLine, ":") {
174
+		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
175
+	}
176
+	field := strings.SplitN(firstLine, ": ", 2)
177
+	cpuinfo := []CPUInfo{}
178
+	featuresLine := ""
179
+	commonCPUInfo := CPUInfo{}
180
+	i := 0
181
+	if strings.TrimSpace(field[0]) == "Processor" {
182
+		commonCPUInfo = CPUInfo{ModelName: field[1]}
183
+		i = -1
184
+	} else {
185
+		v, err := strconv.ParseUint(field[1], 0, 32)
186
+		if err != nil {
187
+			return nil, err
188
+		}
189
+		firstcpu := CPUInfo{Processor: uint(v)}
190
+		cpuinfo = []CPUInfo{firstcpu}
191
+	}
192
+
193
+	for scanner.Scan() {
194
+		line := scanner.Text()
195
+		if !strings.Contains(line, ":") {
196
+			continue
197
+		}
198
+		field := strings.SplitN(line, ": ", 2)
199
+		switch strings.TrimSpace(field[0]) {
200
+		case "processor":
201
+			cpuinfo = append(cpuinfo, commonCPUInfo) // start of the next processor
202
+			i++
203
+			v, err := strconv.ParseUint(field[1], 0, 32)
204
+			if err != nil {
205
+				return nil, err
206
+			}
207
+			cpuinfo[i].Processor = uint(v)
208
+		case "BogoMIPS":
209
+			if i == -1 {
210
+				cpuinfo = append(cpuinfo, commonCPUInfo) // There is only one processor
211
+				i++
212
+				cpuinfo[i].Processor = 0
213
+			}
214
+			v, err := strconv.ParseFloat(field[1], 64)
215
+			if err != nil {
216
+				return nil, err
217
+			}
218
+			cpuinfo[i].BogoMips = v
219
+		case "Features":
220
+			featuresLine = line
221
+		case "model name":
222
+			cpuinfo[i].ModelName = field[1]
223
+		}
224
+	}
225
+	fields := strings.SplitN(featuresLine, ": ", 2)
226
+	for i := range cpuinfo {
227
+		cpuinfo[i].Flags = strings.Fields(fields[1])
228
+	}
229
+	return cpuinfo, nil
166 230
 
167 231
 }
232
+
233
+func parseCPUInfoS390X(info []byte) ([]CPUInfo, error) {
234
+	scanner := bufio.NewScanner(bytes.NewReader(info))
235
+
236
+	firstLine := firstNonEmptyLine(scanner)
237
+	if !strings.HasPrefix(firstLine, "vendor_id") || !strings.Contains(firstLine, ":") {
238
+		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
239
+	}
240
+	field := strings.SplitN(firstLine, ": ", 2)
241
+	cpuinfo := []CPUInfo{}
242
+	commonCPUInfo := CPUInfo{VendorID: field[1]}
243
+
244
+	for scanner.Scan() {
245
+		line := scanner.Text()
246
+		if !strings.Contains(line, ":") {
247
+			continue
248
+		}
249
+		field := strings.SplitN(line, ": ", 2)
250
+		switch strings.TrimSpace(field[0]) {
251
+		case "bogomips per cpu":
252
+			v, err := strconv.ParseFloat(field[1], 64)
253
+			if err != nil {
254
+				return nil, err
255
+			}
256
+			commonCPUInfo.BogoMips = v
257
+		case "features":
258
+			commonCPUInfo.Flags = strings.Fields(field[1])
259
+		}
260
+		if strings.HasPrefix(line, "processor") {
261
+			match := cpuinfoS390XProcessorRegexp.FindStringSubmatch(line)
262
+			if len(match) < 2 {
263
+				return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
264
+			}
265
+			cpu := commonCPUInfo
266
+			v, err := strconv.ParseUint(match[1], 0, 32)
267
+			if err != nil {
268
+				return nil, err
269
+			}
270
+			cpu.Processor = uint(v)
271
+			cpuinfo = append(cpuinfo, cpu)
272
+		}
273
+		if strings.HasPrefix(line, "cpu number") {
274
+			break
275
+		}
276
+	}
277
+
278
+	i := 0
279
+	for scanner.Scan() {
280
+		line := scanner.Text()
281
+		if !strings.Contains(line, ":") {
282
+			continue
283
+		}
284
+		field := strings.SplitN(line, ": ", 2)
285
+		switch strings.TrimSpace(field[0]) {
286
+		case "cpu number":
287
+			i++
288
+		case "cpu MHz dynamic":
289
+			clock := cpuinfoClockRegexp.FindString(strings.TrimSpace(field[1]))
290
+			v, err := strconv.ParseFloat(clock, 64)
291
+			if err != nil {
292
+				return nil, err
293
+			}
294
+			cpuinfo[i].CPUMHz = v
295
+		case "physical id":
296
+			cpuinfo[i].PhysicalID = field[1]
297
+		case "core id":
298
+			cpuinfo[i].CoreID = field[1]
299
+		case "cpu cores":
300
+			v, err := strconv.ParseUint(field[1], 0, 32)
301
+			if err != nil {
302
+				return nil, err
303
+			}
304
+			cpuinfo[i].CPUCores = uint(v)
305
+		case "siblings":
306
+			v, err := strconv.ParseUint(field[1], 0, 32)
307
+			if err != nil {
308
+				return nil, err
309
+			}
310
+			cpuinfo[i].Siblings = uint(v)
311
+		}
312
+	}
313
+
314
+	return cpuinfo, nil
315
+}
316
+
317
+func parseCPUInfoMips(info []byte) ([]CPUInfo, error) {
318
+	scanner := bufio.NewScanner(bytes.NewReader(info))
319
+
320
+	// find the first "processor" line
321
+	firstLine := firstNonEmptyLine(scanner)
322
+	if !strings.HasPrefix(firstLine, "system type") || !strings.Contains(firstLine, ":") {
323
+		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
324
+	}
325
+	field := strings.SplitN(firstLine, ": ", 2)
326
+	cpuinfo := []CPUInfo{}
327
+	systemType := field[1]
328
+
329
+	i := 0
330
+
331
+	for scanner.Scan() {
332
+		line := scanner.Text()
333
+		if !strings.Contains(line, ":") {
334
+			continue
335
+		}
336
+		field := strings.SplitN(line, ": ", 2)
337
+		switch strings.TrimSpace(field[0]) {
338
+		case "processor":
339
+			v, err := strconv.ParseUint(field[1], 0, 32)
340
+			if err != nil {
341
+				return nil, err
342
+			}
343
+			i = int(v)
344
+			cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor
345
+			cpuinfo[i].Processor = uint(v)
346
+			cpuinfo[i].VendorID = systemType
347
+		case "cpu model":
348
+			cpuinfo[i].ModelName = field[1]
349
+		case "BogoMIPS":
350
+			v, err := strconv.ParseFloat(field[1], 64)
351
+			if err != nil {
352
+				return nil, err
353
+			}
354
+			cpuinfo[i].BogoMips = v
355
+		}
356
+	}
357
+	return cpuinfo, nil
358
+}
359
+
360
+func parseCPUInfoPPC(info []byte) ([]CPUInfo, error) {
361
+	scanner := bufio.NewScanner(bytes.NewReader(info))
362
+
363
+	firstLine := firstNonEmptyLine(scanner)
364
+	if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
365
+		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
366
+	}
367
+	field := strings.SplitN(firstLine, ": ", 2)
368
+	v, err := strconv.ParseUint(field[1], 0, 32)
369
+	if err != nil {
370
+		return nil, err
371
+	}
372
+	firstcpu := CPUInfo{Processor: uint(v)}
373
+	cpuinfo := []CPUInfo{firstcpu}
374
+	i := 0
375
+
376
+	for scanner.Scan() {
377
+		line := scanner.Text()
378
+		if !strings.Contains(line, ":") {
379
+			continue
380
+		}
381
+		field := strings.SplitN(line, ": ", 2)
382
+		switch strings.TrimSpace(field[0]) {
383
+		case "processor":
384
+			cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor
385
+			i++
386
+			v, err := strconv.ParseUint(field[1], 0, 32)
387
+			if err != nil {
388
+				return nil, err
389
+			}
390
+			cpuinfo[i].Processor = uint(v)
391
+		case "cpu":
392
+			cpuinfo[i].VendorID = field[1]
393
+		case "clock":
394
+			clock := cpuinfoClockRegexp.FindString(strings.TrimSpace(field[1]))
395
+			v, err := strconv.ParseFloat(clock, 64)
396
+			if err != nil {
397
+				return nil, err
398
+			}
399
+			cpuinfo[i].CPUMHz = v
400
+		}
401
+	}
402
+	return cpuinfo, nil
403
+}
404
+
405
+func parseCPUInfoRISCV(info []byte) ([]CPUInfo, error) {
406
+	scanner := bufio.NewScanner(bytes.NewReader(info))
407
+
408
+	firstLine := firstNonEmptyLine(scanner)
409
+	if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
410
+		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
411
+	}
412
+	field := strings.SplitN(firstLine, ": ", 2)
413
+	v, err := strconv.ParseUint(field[1], 0, 32)
414
+	if err != nil {
415
+		return nil, err
416
+	}
417
+	firstcpu := CPUInfo{Processor: uint(v)}
418
+	cpuinfo := []CPUInfo{firstcpu}
419
+	i := 0
420
+
421
+	for scanner.Scan() {
422
+		line := scanner.Text()
423
+		if !strings.Contains(line, ":") {
424
+			continue
425
+		}
426
+		field := strings.SplitN(line, ": ", 2)
427
+		switch strings.TrimSpace(field[0]) {
428
+		case "processor":
429
+			v, err := strconv.ParseUint(field[1], 0, 32)
430
+			if err != nil {
431
+				return nil, err
432
+			}
433
+			i = int(v)
434
+			cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor
435
+			cpuinfo[i].Processor = uint(v)
436
+		case "hart":
437
+			cpuinfo[i].CoreID = field[1]
438
+		case "isa":
439
+			cpuinfo[i].ModelName = field[1]
440
+		}
441
+	}
442
+	return cpuinfo, nil
443
+}
444
+
445
+func parseCPUInfoDummy(_ []byte) ([]CPUInfo, error) { // nolint:unused,deadcode
446
+	return nil, errors.New("not implemented")
447
+}
448
+
449
+// firstNonEmptyLine advances the scanner to the first non-empty line
450
+// and returns the contents of that line
451
+func firstNonEmptyLine(scanner *bufio.Scanner) string {
452
+	for scanner.Scan() {
453
+		line := scanner.Text()
454
+		if strings.TrimSpace(line) != "" {
455
+			return line
456
+		}
457
+	}
458
+	return ""
459
+}
168 460
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+// +build linux
14
+// +build arm arm64
15
+
16
+package procfs
17
+
18
+var parseCPUInfo = parseCPUInfoARM
0 19
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+// +build linux
14
+// +build mips mipsle mips64 mips64le
15
+
16
+package procfs
17
+
18
+var parseCPUInfo = parseCPUInfoMips
0 19
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+// +build linux
14
+// +build !386,!amd64,!arm,!arm64,!mips,!mips64,!mips64le,!mipsle,!ppc64,!ppc64le,!riscv64,!s390x
15
+
16
+package procfs
17
+
18
+var parseCPUInfo = parseCPUInfoDummy
0 19
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+// +build linux
14
+// +build ppc64 ppc64le
15
+
16
+package procfs
17
+
18
+var parseCPUInfo = parseCPUInfoPPC
0 19
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+// +build linux
14
+// +build riscv riscv64
15
+
16
+package procfs
17
+
18
+var parseCPUInfo = parseCPUInfoRISCV
0 19
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+// +build linux
14
+
15
+package procfs
16
+
17
+var parseCPUInfo = parseCPUInfoS390X
0 18
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+// +build linux
14
+// +build 386 amd64
15
+
16
+package procfs
17
+
18
+var parseCPUInfo = parseCPUInfoX86
... ...
@@ -55,12 +55,12 @@ func (fs FS) Crypto() ([]Crypto, error) {
55 55
 	path := fs.proc.Path("crypto")
56 56
 	b, err := util.ReadFileNoStat(path)
57 57
 	if err != nil {
58
-		return nil, fmt.Errorf("error reading crypto %s: %s", path, err)
58
+		return nil, fmt.Errorf("error reading crypto %q: %w", path, err)
59 59
 	}
60 60
 
61 61
 	crypto, err := parseCrypto(bytes.NewReader(b))
62 62
 	if err != nil {
63
-		return nil, fmt.Errorf("error parsing crypto %s: %s", path, err)
63
+		return nil, fmt.Errorf("error parsing crypto %q: %w", path, err)
64 64
 	}
65 65
 
66 66
 	return crypto, nil
... ...
@@ -31,7 +31,7 @@
31 31
 //    		log.Fatalf("could not get process: %s", err)
32 32
 //    	}
33 33
 //
34
-//    	stat, err := p.NewStat()
34
+//    	stat, err := p.Stat()
35 35
 //    	if err != nil {
36 36
 //    		log.Fatalf("could not get process stat: %s", err)
37 37
 //    	}
... ...
@@ -111,7 +111,7 @@ Max core file size        0                    unlimited            bytes
111 111
 Max resident set          unlimited            unlimited            bytes
112 112
 Max processes             62898                62898                processes
113 113
 Max open files            2048                 4096                 files
114
-Max locked memory         65536                65536                bytes
114
+Max locked memory         18446744073708503040 18446744073708503040 bytes
115 115
 Max address space         8589934592           unlimited            bytes
116 116
 Max file locks            unlimited            unlimited            locks
117 117
 Max pending signals       62898                62898                signals
... ...
@@ -173,6 +173,283 @@ Lines: 1
173 173
 411605849 93680043 79
174 174
 Mode: 644
175 175
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
176
+Path: fixtures/proc/26231/smaps
177
+Lines: 252
178
+00400000-00cb1000 r-xp 00000000 fd:01 952273                             /bin/alertmanager
179
+Size:               8900 kB
180
+KernelPageSize:        4 kB
181
+MMUPageSize:           4 kB
182
+Rss:                2952 kB
183
+Pss:                2952 kB
184
+Shared_Clean:          0 kB
185
+Shared_Dirty:          0 kB
186
+Private_Clean:      2952 kB
187
+Private_Dirty:         0 kB
188
+Referenced:         2864 kB
189
+Anonymous:             0 kB
190
+LazyFree:              0 kB
191
+AnonHugePages:         0 kB
192
+ShmemPmdMapped:        0 kB
193
+Shared_Hugetlb:        0 kB
194
+Private_Hugetlb:       0 kB
195
+Swap:                  0 kB
196
+SwapPss:               0 kB
197
+Locked:                0 kB
198
+VmFlags: rd ex mr mw me dw sd 
199
+00cb1000-016b0000 r--p 008b1000 fd:01 952273                             /bin/alertmanager
200
+Size:              10236 kB
201
+KernelPageSize:        4 kB
202
+MMUPageSize:           4 kB
203
+Rss:                6152 kB
204
+Pss:                6152 kB
205
+Shared_Clean:          0 kB
206
+Shared_Dirty:          0 kB
207
+Private_Clean:      6152 kB
208
+Private_Dirty:         0 kB
209
+Referenced:         5308 kB
210
+Anonymous:             0 kB
211
+LazyFree:              0 kB
212
+AnonHugePages:         0 kB
213
+ShmemPmdMapped:        0 kB
214
+Shared_Hugetlb:        0 kB
215
+Private_Hugetlb:       0 kB
216
+Swap:                  0 kB
217
+SwapPss:               0 kB
218
+Locked:                0 kB
219
+VmFlags: rd mr mw me dw sd 
220
+016b0000-0171a000 rw-p 012b0000 fd:01 952273                             /bin/alertmanager
221
+Size:                424 kB
222
+KernelPageSize:        4 kB
223
+MMUPageSize:           4 kB
224
+Rss:                 176 kB
225
+Pss:                 176 kB
226
+Shared_Clean:          0 kB
227
+Shared_Dirty:          0 kB
228
+Private_Clean:        84 kB
229
+Private_Dirty:        92 kB
230
+Referenced:          176 kB
231
+Anonymous:            92 kB
232
+LazyFree:              0 kB
233
+AnonHugePages:         0 kB
234
+ShmemPmdMapped:        0 kB
235
+Shared_Hugetlb:        0 kB
236
+Private_Hugetlb:       0 kB
237
+Swap:                 12 kB
238
+SwapPss:              12 kB
239
+Locked:                0 kB
240
+VmFlags: rd wr mr mw me dw ac sd 
241
+0171a000-0173f000 rw-p 00000000 00:00 0 
242
+Size:                148 kB
243
+KernelPageSize:        4 kB
244
+MMUPageSize:           4 kB
245
+Rss:                  76 kB
246
+Pss:                  76 kB
247
+Shared_Clean:          0 kB
248
+Shared_Dirty:          0 kB
249
+Private_Clean:         0 kB
250
+Private_Dirty:        76 kB
251
+Referenced:           76 kB
252
+Anonymous:            76 kB
253
+LazyFree:              0 kB
254
+AnonHugePages:         0 kB
255
+ShmemPmdMapped:        0 kB
256
+Shared_Hugetlb:        0 kB
257
+Private_Hugetlb:       0 kB
258
+Swap:                  0 kB
259
+SwapPss:               0 kB
260
+Locked:                0 kB
261
+VmFlags: rd wr mr mw me ac sd 
262
+c000000000-c000400000 rw-p 00000000 00:00 0 
263
+Size:               4096 kB
264
+KernelPageSize:        4 kB
265
+MMUPageSize:           4 kB
266
+Rss:                2564 kB
267
+Pss:                2564 kB
268
+Shared_Clean:          0 kB
269
+Shared_Dirty:          0 kB
270
+Private_Clean:        20 kB
271
+Private_Dirty:      2544 kB
272
+Referenced:         2544 kB
273
+Anonymous:          2564 kB
274
+LazyFree:              0 kB
275
+AnonHugePages:         0 kB
276
+ShmemPmdMapped:        0 kB
277
+Shared_Hugetlb:        0 kB
278
+Private_Hugetlb:       0 kB
279
+Swap:               1100 kB
280
+SwapPss:            1100 kB
281
+Locked:                0 kB
282
+VmFlags: rd wr mr mw me ac sd 
283
+c000400000-c001600000 rw-p 00000000 00:00 0 
284
+Size:              18432 kB
285
+KernelPageSize:        4 kB
286
+MMUPageSize:           4 kB
287
+Rss:               16024 kB
288
+Pss:               16024 kB
289
+Shared_Clean:          0 kB
290
+Shared_Dirty:          0 kB
291
+Private_Clean:      5864 kB
292
+Private_Dirty:     10160 kB
293
+Referenced:        11944 kB
294
+Anonymous:         16024 kB
295
+LazyFree:           5848 kB
296
+AnonHugePages:         0 kB
297
+ShmemPmdMapped:        0 kB
298
+Shared_Hugetlb:        0 kB
299
+Private_Hugetlb:       0 kB
300
+Swap:                440 kB
301
+SwapPss:             440 kB
302
+Locked:                0 kB
303
+VmFlags: rd wr mr mw me ac sd nh 
304
+c001600000-c004000000 rw-p 00000000 00:00 0 
305
+Size:              43008 kB
306
+KernelPageSize:        4 kB
307
+MMUPageSize:           4 kB
308
+Rss:                   0 kB
309
+Pss:                   0 kB
310
+Shared_Clean:          0 kB
311
+Shared_Dirty:          0 kB
312
+Private_Clean:         0 kB
313
+Private_Dirty:         0 kB
314
+Referenced:            0 kB
315
+Anonymous:             0 kB
316
+LazyFree:              0 kB
317
+AnonHugePages:         0 kB
318
+ShmemPmdMapped:        0 kB
319
+Shared_Hugetlb:        0 kB
320
+Private_Hugetlb:       0 kB
321
+Swap:                  0 kB
322
+SwapPss:               0 kB
323
+Locked:                0 kB
324
+VmFlags: rd wr mr mw me ac sd 
325
+7f0ab95ca000-7f0abbb7b000 rw-p 00000000 00:00 0 
326
+Size:              38596 kB
327
+KernelPageSize:        4 kB
328
+MMUPageSize:           4 kB
329
+Rss:                1992 kB
330
+Pss:                1992 kB
331
+Shared_Clean:          0 kB
332
+Shared_Dirty:          0 kB
333
+Private_Clean:       476 kB
334
+Private_Dirty:      1516 kB
335
+Referenced:         1828 kB
336
+Anonymous:          1992 kB
337
+LazyFree:              0 kB
338
+AnonHugePages:         0 kB
339
+ShmemPmdMapped:        0 kB
340
+Shared_Hugetlb:        0 kB
341
+Private_Hugetlb:       0 kB
342
+Swap:                384 kB
343
+SwapPss:             384 kB
344
+Locked:                0 kB
345
+VmFlags: rd wr mr mw me ac sd 
346
+7ffc07ecf000-7ffc07ef0000 rw-p 00000000 00:00 0                          [stack]
347
+Size:                132 kB
348
+KernelPageSize:        4 kB
349
+MMUPageSize:           4 kB
350
+Rss:                   8 kB
351
+Pss:                   8 kB
352
+Shared_Clean:          0 kB
353
+Shared_Dirty:          0 kB
354
+Private_Clean:         0 kB
355
+Private_Dirty:         8 kB
356
+Referenced:            8 kB
357
+Anonymous:             8 kB
358
+LazyFree:              0 kB
359
+AnonHugePages:         0 kB
360
+ShmemPmdMapped:        0 kB
361
+Shared_Hugetlb:        0 kB
362
+Private_Hugetlb:       0 kB
363
+Swap:                  4 kB
364
+SwapPss:               4 kB
365
+Locked:                0 kB
366
+VmFlags: rd wr mr mw me gd ac 
367
+7ffc07f9e000-7ffc07fa1000 r--p 00000000 00:00 0                          [vvar]
368
+Size:                 12 kB
369
+KernelPageSize:        4 kB
370
+MMUPageSize:           4 kB
371
+Rss:                   0 kB
372
+Pss:                   0 kB
373
+Shared_Clean:          0 kB
374
+Shared_Dirty:          0 kB
375
+Private_Clean:         0 kB
376
+Private_Dirty:         0 kB
377
+Referenced:            0 kB
378
+Anonymous:             0 kB
379
+LazyFree:              0 kB
380
+AnonHugePages:         0 kB
381
+ShmemPmdMapped:        0 kB
382
+Shared_Hugetlb:        0 kB
383
+Private_Hugetlb:       0 kB
384
+Swap:                  0 kB
385
+SwapPss:               0 kB
386
+Locked:                0 kB
387
+VmFlags: rd mr pf io de dd sd 
388
+7ffc07fa1000-7ffc07fa3000 r-xp 00000000 00:00 0                          [vdso]
389
+Size:                  8 kB
390
+KernelPageSize:        4 kB
391
+MMUPageSize:           4 kB
392
+Rss:                   4 kB
393
+Pss:                   0 kB
394
+Shared_Clean:          4 kB
395
+Shared_Dirty:          0 kB
396
+Private_Clean:         0 kB
397
+Private_Dirty:         0 kB
398
+Referenced:            4 kB
399
+Anonymous:             0 kB
400
+LazyFree:              0 kB
401
+AnonHugePages:         0 kB
402
+ShmemPmdMapped:        0 kB
403
+Shared_Hugetlb:        0 kB
404
+Private_Hugetlb:       0 kB
405
+Swap:                  0 kB
406
+SwapPss:               0 kB
407
+Locked:                0 kB
408
+VmFlags: rd ex mr mw me de sd 
409
+ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
410
+Size:                  4 kB
411
+KernelPageSize:        4 kB
412
+MMUPageSize:           4 kB
413
+Rss:                   0 kB
414
+Pss:                   0 kB
415
+Shared_Clean:          0 kB
416
+Shared_Dirty:          0 kB
417
+Private_Clean:         0 kB
418
+Private_Dirty:         0 kB
419
+Referenced:            0 kB
420
+Anonymous:             0 kB
421
+LazyFree:              0 kB
422
+AnonHugePages:         0 kB
423
+ShmemPmdMapped:        0 kB
424
+Shared_Hugetlb:        0 kB
425
+Private_Hugetlb:       0 kB
426
+Swap:                  0 kB
427
+SwapPss:               0 kB
428
+Locked:                0 kB
429
+VmFlags: rd ex 
430
+Mode: 644
431
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
432
+Path: fixtures/proc/26231/smaps_rollup
433
+Lines: 17
434
+00400000-ffffffffff601000 ---p 00000000 00:00 0                          [rollup]
435
+Rss:               29948 kB
436
+Pss:               29944 kB
437
+Shared_Clean:          4 kB
438
+Shared_Dirty:          0 kB
439
+Private_Clean:     15548 kB
440
+Private_Dirty:     14396 kB
441
+Referenced:        24752 kB
442
+Anonymous:         20756 kB
443
+LazyFree:           5848 kB
444
+AnonHugePages:         0 kB
445
+ShmemPmdMapped:        0 kB
446
+Shared_Hugetlb:        0 kB
447
+Private_Hugetlb:       0 kB
448
+Swap:               1940 kB
449
+SwapPss:            1940 kB
450
+Locked:                0 kB
451
+Mode: 644
452
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
176 453
 Path: fixtures/proc/26231/stat
177 454
 Lines: 1
178 455
 26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0
... ...
@@ -190,7 +467,7 @@ Pid:	26231
190 190
 PPid:	1
191 191
 TracerPid:	0
192 192
 Uid:	1000	1000	1000	0
193
-Gid:	0	0	0	0
193
+Gid:	1001	1001	1001	0
194 194
 FDSize:	128
195 195
 Groups:
196 196
 NStgid:	1
... ...
@@ -235,6 +512,11 @@ voluntary_ctxt_switches:	4742839
235 235
 nonvoluntary_ctxt_switches:	1727500
236 236
 Mode: 644
237 237
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
238
+Path: fixtures/proc/26231/wchan
239
+Lines: 1
240
+poll_schedule_timeoutEOF
241
+Mode: 664
242
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
238 243
 Directory: fixtures/proc/26232
239 244
 Mode: 755
240 245
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
... ...
@@ -310,6 +592,11 @@ Lines: 1
310 310
 33 (ata_sff) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 5 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0
311 311
 Mode: 644
312 312
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
313
+Path: fixtures/proc/26232/wchan
314
+Lines: 1
315
+0EOF
316
+Mode: 664
317
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
313 318
 Directory: fixtures/proc/26233
314 319
 Mode: 755
315 320
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
... ...
@@ -357,6 +644,11 @@ Node 0, zone    DMA32    759    572    791    475    194     45     12      0
357 357
 Node 0, zone   Normal   4381   1093    185   1530    567    102      4      0      0      0      0
358 358
 Mode: 644
359 359
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
360
+Path: fixtures/proc/cmdline
361
+Lines: 1
362
+BOOT_IMAGE=/vmlinuz-5.11.0-22-generic root=UUID=456a0345-450d-4f7b-b7c9-43e3241d99ad ro quiet splash vt.handoff=7
363
+Mode: 444
364
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
360 365
 Path: fixtures/proc/cpuinfo
361 366
 Lines: 216
362 367
 processor	: 0
... ...
@@ -793,7 +1085,6 @@ internal     : yes
793 793
 type         : skcipher
794 794
 async        : yes
795 795
 blocksize    : 1
796
-min keysize  : 16
797 796
 max keysize  : 32
798 797
 ivsize       : 16
799 798
 chunksize    : 16
... ...
@@ -1552,9 +1843,10 @@ min keysize  : 16
1552 1552
 max keysize  : 32
1553 1553
 
1554 1554
 Mode: 444
1555
+Mode: 644
1555 1556
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1556 1557
 Path: fixtures/proc/diskstats
1557
-Lines: 49
1558
+Lines: 52
1558 1559
    1       0 ram0 0 0 0 0 0 0 0 0 0 0 0
1559 1560
    1       1 ram1 0 0 0 0 0 0 0 0 0 0 0
1560 1561
    1       2 ram2 0 0 0 0 0 0 0 0 0 0 0
... ...
@@ -1604,11 +1896,45 @@ Lines: 49
1604 1604
    8       0 sdb 326552 841 9657779 84 41822 2895 1972905 5007 0 60730 67070 68851 0 1925173784 11130
1605 1605
    8       1 sdb1 231 3 34466 4 24 23 106 0 0 64 64 0 0 0 0
1606 1606
    8       2 sdb2 326310 838 9622281 67 40726 2872 1972799 4924 0 58250 64567 68851 0 1925173784 11130
1607
+   8       0 sdc 14202 71 579164 21861 2995 1589 180500 40875 0 11628 55200 0 0 0 0 127 182
1608
+   8       1 sdc1 1027 0 13795 5021 2 0 4096 3 0 690 4579 0 0 0 0 0 0
1609
+   8       2 sdc2 13126 71 561749 16802 2830 1589 176404 40620 0 10931 50449 0 0 0 0 0 0
1607 1610
 Mode: 664
1608 1611
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1609 1612
 Directory: fixtures/proc/fs
1610 1613
 Mode: 755
1611 1614
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1615
+Directory: fixtures/proc/fs/fscache
1616
+Mode: 755
1617
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1618
+Path: fixtures/proc/fs/fscache/stats
1619
+Lines: 24
1620
+FS-Cache statistics
1621
+Cookies: idx=3 dat=67877 spc=0
1622
+Objects: alc=67473 nal=0 avl=67473 ded=388
1623
+ChkAux : non=12 ok=33 upd=44 obs=55
1624
+Pages  : mrk=547164 unc=364577
1625
+Acquire: n=67880 nul=98 noc=25 ok=67780 nbf=39 oom=26
1626
+Lookups: n=67473 neg=67470 pos=58 crt=67473 tmo=85
1627
+Invals : n=14 run=13
1628
+Updates: n=7 nul=3 run=8
1629
+Relinqs: n=394 nul=1 wcr=2 rtr=3
1630
+AttrChg: n=6 ok=5 nbf=4 oom=3 run=2
1631
+Allocs : n=20 ok=19 wt=18 nbf=17 int=16
1632
+Allocs : ops=15 owt=14 abt=13
1633
+Retrvls: n=151959 ok=82823 wt=23467 nod=69136 nbf=15 int=69 oom=43
1634
+Retrvls: ops=151959 owt=42747 abt=44
1635
+Stores : n=225565 ok=225565 agn=12 nbf=13 oom=14
1636
+Stores : ops=69156 run=294721 pgs=225565 rxd=225565 olm=43
1637
+VmScan : nos=364512 gon=2 bsy=43 can=12 wt=66
1638
+Ops    : pend=42753 run=221129 enq=628798 can=11 rej=88
1639
+Ops    : ini=377538 dfr=27 rel=377538 gc=37
1640
+CacheOp: alo=1 luo=2 luc=3 gro=4
1641
+CacheOp: inv=5 upo=6 dro=7 pto=8 atc=9 syn=10
1642
+CacheOp: rap=11 ras=12 alp=13 als=14 wrp=15 ucp=16 dsp=17
1643
+CacheEv: nsp=18 stl=19 rtr=20 cul=21EOF
1644
+Mode: 644
1645
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1612 1646
 Directory: fixtures/proc/fs/xfs
1613 1647
 Mode: 755
1614 1648
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
... ...
@@ -1645,7 +1971,7 @@ Lines: 1
1645 1645
 Mode: 444
1646 1646
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1647 1647
 Path: fixtures/proc/mdstat
1648
-Lines: 56
1648
+Lines: 60
1649 1649
 Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
1650 1650
 
1651 1651
 md3 : active raid6 sda1[8] sdh1[7] sdg1[6] sdf1[5] sde1[11] sdd1[3] sdc1[10] sdb1[9] sdd1[10](S) sdd2[11](S)
... ...
@@ -1668,6 +1994,10 @@ md8 : active raid1 sdb1[1] sda1[0] sdc[2](S) sde[3](S)
1668 1668
       195310144 blocks [2/2] [UU]
1669 1669
       [=>...................]  resync =  8.5% (16775552/195310144) finish=17.0min speed=259783K/sec
1670 1670
 
1671
+md201 : active raid1 sda3[0] sdb3[1]
1672
+      1993728 blocks super 1.2 [2/2] [UU]
1673
+      [=>...................]  check =  5.7% (114176/1993728) finish=0.2min speed=114176K/sec
1674
+
1671 1675
 md7 : active raid6 sdb1[0] sde1[3] sdd1[2] sdc1[1](F)
1672 1676
       7813735424 blocks super 1.2 level 6, 512k chunk, algorithm 2 [4/3] [U_UU]
1673 1677
       bitmap: 0/30 pages [0KB], 65536KB chunk
... ...
@@ -1804,6 +2134,24 @@ Lines: 6
1804 1804
        4    1FB3C        0          1282A8F                0
1805 1805
 Mode: 644
1806 1806
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1807
+Path: fixtures/proc/net/protocols
1808
+Lines: 14
1809
+protocol  size sockets  memory press maxhdr  slab module     cl co di ac io in de sh ss gs se re sp bi br ha uh gp em
1810
+PACKET    1344      2      -1   NI       0   no   kernel      n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n
1811
+PINGv6    1112      0      -1   NI       0   yes  kernel      y  y  y  n  n  y  n  n  y  y  y  y  n  y  y  y  y  y  n
1812
+RAWv6     1112      1      -1   NI       0   yes  kernel      y  y  y  n  y  y  y  n  y  y  y  y  n  y  y  y  y  n  n
1813
+UDPLITEv6 1216      0      57   NI       0   yes  kernel      y  y  y  n  y  y  y  n  y  y  y  y  n  n  n  y  y  y  n
1814
+UDPv6     1216     10      57   NI       0   yes  kernel      y  y  y  n  y  y  y  n  y  y  y  y  n  n  n  y  y  y  n
1815
+TCPv6     2144   1937  1225378   no     320   yes  kernel      y  y  y  y  y  y  y  y  y  y  y  y  y  n  y  y  y  y  y
1816
+UNIX      1024    120      -1   NI       0   yes  kernel      n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n
1817
+UDP-Lite  1024      0      57   NI       0   yes  kernel      y  y  y  n  y  y  y  n  y  y  y  y  y  n  n  y  y  y  n
1818
+PING       904      0      -1   NI       0   yes  kernel      y  y  y  n  n  y  n  n  y  y  y  y  n  y  y  y  y  y  n
1819
+RAW        912      0      -1   NI       0   yes  kernel      y  y  y  n  y  y  y  n  y  y  y  y  n  y  y  y  y  n  n
1820
+UDP       1024     73      57   NI       0   yes  kernel      y  y  y  n  y  y  y  n  y  y  y  y  y  n  n  y  y  y  n
1821
+TCP       1984  93064  1225378   yes     320   yes  kernel      y  y  y  y  y  y  y  y  y  y  y  y  y  n  y  y  y  y  y
1822
+NETLINK   1040     16      -1   NI       0   no   kernel      n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n
1823
+Mode: 444
1824
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1807 1825
 Directory: fixtures/proc/net/rpc
1808 1826
 Mode: 755
1809 1827
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
... ...
@@ -1861,10 +2209,42 @@ Lines: 1
1861 1861
 00015c73 00020e76 F0000769 00000000
1862 1862
 Mode: 644
1863 1863
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1864
+Directory: fixtures/proc/net/stat
1865
+Mode: 755
1866
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1867
+Path: fixtures/proc/net/stat/arp_cache
1868
+Lines: 3
1869
+entries  allocs destroys hash_grows  lookups hits  res_failed  rcv_probes_mcast rcv_probes_ucast  periodic_gc_runs forced_gc_runs unresolved_discards table_fulls
1870
+00000014  00000001 00000002 00000003  00000004 00000005  00000006  00000007 00000008  00000009 0000000a 0000000b 0000000c
1871
+00000014  0000000d 0000000e 0000000f  00000010 00000011  00000012  00000013 00000014  00000015 00000016 00000017 00000018
1872
+Mode: 644
1873
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1874
+Path: fixtures/proc/net/stat/ndisc_cache
1875
+Lines: 3
1876
+entries  allocs destroys hash_grows  lookups hits  res_failed  rcv_probes_mcast rcv_probes_ucast  periodic_gc_runs forced_gc_runs unresolved_discards table_fulls
1877
+00000024  000000f0 000000f1 000000f2  000000f3 000000f4  000000f5  000000f6 000000f7  000000f8 000000f9 000000fa 000000fb
1878
+00000024  000000fc 000000fd 000000fe  000000ff 00000100  00000101  00000102 00000103  00000104 00000105 00000106 00000107
1879
+Mode: 644
1880
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1881
+Path: fixtures/proc/net/tcp
1882
+Lines: 4
1883
+  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
1884
+   0: 0500000A:0016 00000000:0000 0A 00000000:00000001 00:00000000 00000000     0        0 2740 1 ffff88003d3af3c0 100 0 0 10 0
1885
+   1: 00000000:0016 00000000:0000 0A 00000001:00000000 00:00000000 00000000     0        0 2740 1 ffff88003d3af3c0 100 0 0 10 0
1886
+   2: 00000000:0016 00000000:0000 0A 00000001:00000001 00:00000000 00000000     0        0 2740 1 ffff88003d3af3c0 100 0 0 10 0
1887
+Mode: 644
1888
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1889
+Path: fixtures/proc/net/tcp6
1890
+Lines: 3
1891
+  sl  local_address                         remote_address                        st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode ref pointer drops
1892
+ 1315: 00000000000000000000000000000000:14EB 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000   981        0 21040 2 0000000013726323 0
1893
+ 6073: 000080FE00000000FFADE15609667CFE:C781 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000  1000        0 11337031 2 00000000b9256fdd 0
1894
+Mode: 644
1895
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1864 1896
 Path: fixtures/proc/net/udp
1865 1897
 Lines: 4
1866 1898
   sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
1867
-   0: 0A000005:0016 00000000:0000 0A 00000000:00000001 00:00000000 00000000     0        0 2740 1 ffff88003d3af3c0 100 0 0 10 0
1899
+   0: 0500000A:0016 00000000:0000 0A 00000000:00000001 00:00000000 00000000     0        0 2740 1 ffff88003d3af3c0 100 0 0 10 0
1868 1900
    1: 00000000:0016 00000000:0000 0A 00000001:00000000 00:00000000 00000000     0        0 2740 1 ffff88003d3af3c0 100 0 0 10 0
1869 1901
    2: 00000000:0016 00000000:0000 0A 00000001:00000001 00:00000000 00000000     0        0 2740 1 ffff88003d3af3c0 100 0 0 10 0
1870 1902
 Mode: 644
... ...
@@ -1967,6 +2347,312 @@ Mode: 644
1967 1967
 Path: fixtures/proc/self
1968 1968
 SymlinkTo: 26231
1969 1969
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1970
+Path: fixtures/proc/slabinfo
1971
+Lines: 302
1972
+slabinfo - version: 2.1
1973
+# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
1974
+pid_3                375    532    576   28    4 : tunables    0    0    0 : slabdata     19     19      0
1975
+pid_2                  3     28    576   28    4 : tunables    0    0    0 : slabdata      1      1      0
1976
+nvidia_p2p_page_cache      0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
1977
+nvidia_pte_cache    9022   9152    368   22    2 : tunables    0    0    0 : slabdata    416    416      0
1978
+nvidia_stack_cache    321    326  12624    2    8 : tunables    0    0    0 : slabdata    163    163      0
1979
+kvm_async_pf           0      0    472   34    4 : tunables    0    0    0 : slabdata      0      0      0
1980
+kvm_vcpu               0      0  15552    2    8 : tunables    0    0    0 : slabdata      0      0      0
1981
+kvm_mmu_page_header      0      0    504   32    4 : tunables    0    0    0 : slabdata      0      0      0
1982
+pte_list_desc          0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
1983
+x86_emulator           0      0   3024   10    8 : tunables    0    0    0 : slabdata      0      0      0
1984
+x86_fpu                0      0   4608    7    8 : tunables    0    0    0 : slabdata      0      0      0
1985
+iwl_cmd_pool:0000:04:00.0      0    128    512   32    4 : tunables    0    0    0 : slabdata      4      4      0
1986
+ext4_groupinfo_4k   3719   3740    480   34    4 : tunables    0    0    0 : slabdata    110    110      0
1987
+bio-6                 32     75    640   25    4 : tunables    0    0    0 : slabdata      3      3      0
1988
+bio-5                 16     48   1344   24    8 : tunables    0    0    0 : slabdata      2      2      0
1989
+bio-4                 17     92   1408   23    8 : tunables    0    0    0 : slabdata      4      4      0
1990
+fat_inode_cache        0      0   1056   31    8 : tunables    0    0    0 : slabdata      0      0      0
1991
+fat_cache              0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
1992
+ovl_aio_req            0      0    512   32    4 : tunables    0    0    0 : slabdata      0      0      0
1993
+ovl_inode              0      0   1000   32    8 : tunables    0    0    0 : slabdata      0      0      0
1994
+squashfs_inode_cache      0      0   1088   30    8 : tunables    0    0    0 : slabdata      0      0      0
1995
+fuse_request           0      0    472   34    4 : tunables    0    0    0 : slabdata      0      0      0
1996
+fuse_inode             0      0   1152   28    8 : tunables    0    0    0 : slabdata      0      0      0
1997
+xfs_dqtrx              0      0    864   37    8 : tunables    0    0    0 : slabdata      0      0      0
1998
+xfs_dquot              0      0    832   39    8 : tunables    0    0    0 : slabdata      0      0      0
1999
+xfs_buf                0      0    768   21    4 : tunables    0    0    0 : slabdata      0      0      0
2000
+xfs_bui_item           0      0    544   30    4 : tunables    0    0    0 : slabdata      0      0      0
2001
+xfs_bud_item           0      0    512   32    4 : tunables    0    0    0 : slabdata      0      0      0
2002
+xfs_cui_item           0      0    768   21    4 : tunables    0    0    0 : slabdata      0      0      0
2003
+xfs_cud_item           0      0    512   32    4 : tunables    0    0    0 : slabdata      0      0      0
2004
+xfs_rui_item           0      0   1024   32    8 : tunables    0    0    0 : slabdata      0      0      0
2005
+xfs_rud_item           0      0    512   32    4 : tunables    0    0    0 : slabdata      0      0      0
2006
+xfs_icr                0      0    520   31    4 : tunables    0    0    0 : slabdata      0      0      0
2007
+xfs_ili                0      0    528   31    4 : tunables    0    0    0 : slabdata      0      0      0
2008
+xfs_inode              0      0   1344   24    8 : tunables    0    0    0 : slabdata      0      0      0
2009
+xfs_efi_item           0      0    768   21    4 : tunables    0    0    0 : slabdata      0      0      0
2010
+xfs_efd_item           0      0    776   21    4 : tunables    0    0    0 : slabdata      0      0      0
2011
+xfs_buf_item           0      0    608   26    4 : tunables    0    0    0 : slabdata      0      0      0
2012
+xf_trans               0      0    568   28    4 : tunables    0    0    0 : slabdata      0      0      0
2013
+xfs_ifork              0      0    376   21    2 : tunables    0    0    0 : slabdata      0      0      0
2014
+xfs_da_state           0      0    816   20    4 : tunables    0    0    0 : slabdata      0      0      0
2015
+xfs_btree_cur          0      0    560   29    4 : tunables    0    0    0 : slabdata      0      0      0
2016
+xfs_bmap_free_item      0      0    400   20    2 : tunables    0    0    0 : slabdata      0      0      0
2017
+xfs_log_ticket         0      0    520   31    4 : tunables    0    0    0 : slabdata      0      0      0
2018
+nfs_direct_cache       0      0    560   29    4 : tunables    0    0    0 : slabdata      0      0      0
2019
+nfs_commit_data        4     28   1152   28    8 : tunables    0    0    0 : slabdata      1      1      0
2020
+nfs_write_data        32     50   1280   25    8 : tunables    0    0    0 : slabdata      2      2      0
2021
+nfs_read_data          0      0   1280   25    8 : tunables    0    0    0 : slabdata      0      0      0
2022
+nfs_inode_cache        0      0   1408   23    8 : tunables    0    0    0 : slabdata      0      0      0
2023
+nfs_page               0      0    512   32    4 : tunables    0    0    0 : slabdata      0      0      0
2024
+rpc_inode_cache        0      0   1024   32    8 : tunables    0    0    0 : slabdata      0      0      0
2025
+rpc_buffers            8     13   2496   13    8 : tunables    0    0    0 : slabdata      1      1      0
2026
+rpc_tasks              8     25    640   25    4 : tunables    0    0    0 : slabdata      1      1      0
2027
+fscache_cookie_jar      1     35    464   35    4 : tunables    0    0    0 : slabdata      1      1      0
2028
+jfs_mp                32     35    464   35    4 : tunables    0    0    0 : slabdata      1      1      0
2029
+jfs_ip                 0      0   1592   20    8 : tunables    0    0    0 : slabdata      0      0      0
2030
+reiser_inode_cache      0      0   1096   29    8 : tunables    0    0    0 : slabdata      0      0      0
2031
+btrfs_end_io_wq        0      0    464   35    4 : tunables    0    0    0 : slabdata      0      0      0
2032
+btrfs_prelim_ref       0      0    424   38    4 : tunables    0    0    0 : slabdata      0      0      0
2033
+btrfs_delayed_extent_op      0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
2034
+btrfs_delayed_data_ref      0      0    448   36    4 : tunables    0    0    0 : slabdata      0      0      0
2035
+btrfs_delayed_tree_ref      0      0    440   37    4 : tunables    0    0    0 : slabdata      0      0      0
2036
+btrfs_delayed_ref_head      0      0    480   34    4 : tunables    0    0    0 : slabdata      0      0      0
2037
+btrfs_inode_defrag      0      0    400   20    2 : tunables    0    0    0 : slabdata      0      0      0
2038
+btrfs_delayed_node      0      0    648   25    4 : tunables    0    0    0 : slabdata      0      0      0
2039
+btrfs_ordered_extent      0      0    752   21    4 : tunables    0    0    0 : slabdata      0      0      0
2040
+btrfs_extent_map       0      0    480   34    4 : tunables    0    0    0 : slabdata      0      0      0
2041
+btrfs_extent_state      0      0    416   39    4 : tunables    0    0    0 : slabdata      0      0      0
2042
+bio-3                 35     92    704   23    4 : tunables    0    0    0 : slabdata      4      4      0
2043
+btrfs_extent_buffer      0      0    600   27    4 : tunables    0    0    0 : slabdata      0      0      0
2044
+btrfs_free_space_bitmap      0      0  12288    2    8 : tunables    0    0    0 : slabdata      0      0      0
2045
+btrfs_free_space       0      0    416   39    4 : tunables    0    0    0 : slabdata      0      0      0
2046
+btrfs_path             0      0    448   36    4 : tunables    0    0    0 : slabdata      0      0      0
2047
+btrfs_trans_handle      0      0    440   37    4 : tunables    0    0    0 : slabdata      0      0      0
2048
+btrfs_inode            0      0   1496   21    8 : tunables    0    0    0 : slabdata      0      0      0
2049
+ext4_inode_cache   84136  84755   1400   23    8 : tunables    0    0    0 : slabdata   3685   3685      0
2050
+ext4_free_data        22     80    392   20    2 : tunables    0    0    0 : slabdata      4      4      0
2051
+ext4_allocation_context      0     70    464   35    4 : tunables    0    0    0 : slabdata      2      2      0
2052
+ext4_prealloc_space     24     74    440   37    4 : tunables    0    0    0 : slabdata      2      2      0
2053
+ext4_system_zone     267    273    376   21    2 : tunables    0    0    0 : slabdata     13     13      0
2054
+ext4_io_end_vec        0     88    368   22    2 : tunables    0    0    0 : slabdata      4      4      0
2055
+ext4_io_end            0     80    400   20    2 : tunables    0    0    0 : slabdata      4      4      0
2056
+ext4_bio_post_read_ctx    128    147    384   21    2 : tunables    0    0    0 : slabdata      7      7      0
2057
+ext4_pending_reservation      0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
2058
+ext4_extent_status  79351  79422    376   21    2 : tunables    0    0    0 : slabdata   3782   3782      0
2059
+jbd2_transaction_s     44    100    640   25    4 : tunables    0    0    0 : slabdata      4      4      0
2060
+jbd2_inode          6785   6840    400   20    2 : tunables    0    0    0 : slabdata    342    342      0
2061
+jbd2_journal_handle      0     80    392   20    2 : tunables    0    0    0 : slabdata      4      4      0
2062
+jbd2_journal_head    824   1944    448   36    4 : tunables    0    0    0 : slabdata     54     54      0
2063
+jbd2_revoke_table_s      4     23    352   23    2 : tunables    0    0    0 : slabdata      1      1      0
2064
+jbd2_revoke_record_s      0    156    416   39    4 : tunables    0    0    0 : slabdata      4      4      0
2065
+ext2_inode_cache       0      0   1144   28    8 : tunables    0    0    0 : slabdata      0      0      0
2066
+mbcache                0      0    392   20    2 : tunables    0    0    0 : slabdata      0      0      0
2067
+dm_thin_new_mapping      0    152    424   38    4 : tunables    0    0    0 : slabdata      4      4      0
2068
+dm_snap_pending_exception      0      0    464   35    4 : tunables    0    0    0 : slabdata      0      0      0
2069
+dm_exception           0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
2070
+dm_dirty_log_flush_entry      0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
2071
+dm_bio_prison_cell_v2      0      0    432   37    4 : tunables    0    0    0 : slabdata      0      0      0
2072
+dm_bio_prison_cell      0    148    432   37    4 : tunables    0    0    0 : slabdata      4      4      0
2073
+kcopyd_job             0      8   3648    8    8 : tunables    0    0    0 : slabdata      1      1      0
2074
+io                     0     32    512   32    4 : tunables    0    0    0 : slabdata      1      1      0
2075
+dm_uevent              0      0   3224   10    8 : tunables    0    0    0 : slabdata      0      0      0
2076
+dax_cache              1     28   1152   28    8 : tunables    0    0    0 : slabdata      1      1      0
2077
+aic94xx_ascb           0      0    576   28    4 : tunables    0    0    0 : slabdata      0      0      0
2078
+aic94xx_dma_token      0      0    384   21    2 : tunables    0    0    0 : slabdata      0      0      0
2079
+asd_sas_event          0      0    512   32    4 : tunables    0    0    0 : slabdata      0      0      0
2080
+sas_task               0      0    704   23    4 : tunables    0    0    0 : slabdata      0      0      0
2081
+qla2xxx_srbs           0      0    832   39    8 : tunables    0    0    0 : slabdata      0      0      0
2082
+sd_ext_cdb             2     22    368   22    2 : tunables    0    0    0 : slabdata      1      1      0
2083
+scsi_sense_cache     258    288    512   32    4 : tunables    0    0    0 : slabdata      9      9      0
2084
+virtio_scsi_cmd       64     75    640   25    4 : tunables    0    0    0 : slabdata      3      3      0
2085
+L2TP/IPv6              0      0   1536   21    8 : tunables    0    0    0 : slabdata      0      0      0
2086
+L2TP/IP                0      0   1408   23    8 : tunables    0    0    0 : slabdata      0      0      0
2087
+ip6-frags              0      0    520   31    4 : tunables    0    0    0 : slabdata      0      0      0
2088
+fib6_nodes             5     32    512   32    4 : tunables    0    0    0 : slabdata      1      1      0
2089
+ip6_dst_cache          4     25    640   25    4 : tunables    0    0    0 : slabdata      1      1      0
2090
+ip6_mrt_cache          0      0    576   28    4 : tunables    0    0    0 : slabdata      0      0      0
2091
+PINGv6                 0      0   1600   20    8 : tunables    0    0    0 : slabdata      0      0      0
2092
+RAWv6                 25     40   1600   20    8 : tunables    0    0    0 : slabdata      2      2      0
2093
+UDPLITEv6              0      0   1728   18    8 : tunables    0    0    0 : slabdata      0      0      0
2094
+UDPv6                  3     54   1728   18    8 : tunables    0    0    0 : slabdata      3      3      0
2095
+tw_sock_TCPv6          0      0    576   28    4 : tunables    0    0    0 : slabdata      0      0      0
2096
+request_sock_TCPv6      0      0    632   25    4 : tunables    0    0    0 : slabdata      0      0      0
2097
+TCPv6                  0     33   2752   11    8 : tunables    0    0    0 : slabdata      3      3      0
2098
+uhci_urb_priv          0      0    392   20    2 : tunables    0    0    0 : slabdata      0      0      0
2099
+sgpool-128             2     14   4544    7    8 : tunables    0    0    0 : slabdata      2      2      0
2100
+sgpool-64              2     13   2496   13    8 : tunables    0    0    0 : slabdata      1      1      0
2101
+sgpool-32              2     44   1472   22    8 : tunables    0    0    0 : slabdata      2      2      0
2102
+sgpool-16              2     68    960   34    8 : tunables    0    0    0 : slabdata      2      2      0
2103
+sgpool-8               2     46    704   23    4 : tunables    0    0    0 : slabdata      2      2      0
2104
+btree_node             0      0    576   28    4 : tunables    0    0    0 : slabdata      0      0      0
2105
+bfq_io_cq              0      0    488   33    4 : tunables    0    0    0 : slabdata      0      0      0
2106
+bfq_queue              0      0    848   38    8 : tunables    0    0    0 : slabdata      0      0      0
2107
+mqueue_inode_cache      1     24   1344   24    8 : tunables    0    0    0 : slabdata      1      1      0
2108
+isofs_inode_cache      0      0    968   33    8 : tunables    0    0    0 : slabdata      0      0      0
2109
+io_kiocb               0      0    640   25    4 : tunables    0    0    0 : slabdata      0      0      0
2110
+kioctx                 0     30   1088   30    8 : tunables    0    0    0 : slabdata      1      1      0
2111
+aio_kiocb              0     28    576   28    4 : tunables    0    0    0 : slabdata      1      1      0
2112
+userfaultfd_ctx_cache      0      0    576   28    4 : tunables    0    0    0 : slabdata      0      0      0
2113
+fanotify_path_event      0      0    392   20    2 : tunables    0    0    0 : slabdata      0      0      0
2114
+fanotify_fid_event      0      0    400   20    2 : tunables    0    0    0 : slabdata      0      0      0
2115
+fsnotify_mark          0      0    408   20    2 : tunables    0    0    0 : slabdata      0      0      0
2116
+dnotify_mark           0      0    416   39    4 : tunables    0    0    0 : slabdata      0      0      0
2117
+dnotify_struct         0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
2118
+dio                    0      0   1088   30    8 : tunables    0    0    0 : slabdata      0      0      0
2119
+bio-2                  4     25    640   25    4 : tunables    0    0    0 : slabdata      1      1      0
2120
+fasync_cache           0      0    384   21    2 : tunables    0    0    0 : slabdata      0      0      0
2121
+audit_tree_mark        0      0    416   39    4 : tunables    0    0    0 : slabdata      0      0      0
2122
+pid_namespace         30     34    480   34    4 : tunables    0    0    0 : slabdata      1      1      0
2123
+posix_timers_cache      0     27    592   27    4 : tunables    0    0    0 : slabdata      1      1      0
2124
+iommu_devinfo         24     32    512   32    4 : tunables    0    0    0 : slabdata      1      1      0
2125
+iommu_domain          10     10   3264   10    8 : tunables    0    0    0 : slabdata      1      1      0
2126
+iommu_iova          8682   8748    448   36    4 : tunables    0    0    0 : slabdata    243    243      0
2127
+UNIX                 529    814   1472   22    8 : tunables    0    0    0 : slabdata     37     37      0
2128
+ip4-frags              0      0    536   30    4 : tunables    0    0    0 : slabdata      0      0      0
2129
+ip_mrt_cache           0      0    576   28    4 : tunables    0    0    0 : slabdata      0      0      0
2130
+UDP-Lite               0      0   1536   21    8 : tunables    0    0    0 : slabdata      0      0      0
2131
+tcp_bind_bucket        7    128    512   32    4 : tunables    0    0    0 : slabdata      4      4      0
2132
+inet_peer_cache        0      0    576   28    4 : tunables    0    0    0 : slabdata      0      0      0
2133
+xfrm_dst_cache         0      0    704   23    4 : tunables    0    0    0 : slabdata      0      0      0
2134
+xfrm_state             0      0   1152   28    8 : tunables    0    0    0 : slabdata      0      0      0
2135
+ip_fib_trie            7     21    384   21    2 : tunables    0    0    0 : slabdata      1      1      0
2136
+ip_fib_alias           9     20    392   20    2 : tunables    0    0    0 : slabdata      1      1      0
2137
+ip_dst_cache          27     84    576   28    4 : tunables    0    0    0 : slabdata      3      3      0
2138
+PING                   0      0   1408   23    8 : tunables    0    0    0 : slabdata      0      0      0
2139
+RAW                   32     46   1408   23    8 : tunables    0    0    0 : slabdata      2      2      0
2140
+UDP                   11    168   1536   21    8 : tunables    0    0    0 : slabdata      8      8      0
2141
+tw_sock_TCP            1     56    576   28    4 : tunables    0    0    0 : slabdata      2      2      0
2142
+request_sock_TCP       0     25    632   25    4 : tunables    0    0    0 : slabdata      1      1      0
2143
+TCP                   10     60   2624   12    8 : tunables    0    0    0 : slabdata      5      5      0
2144
+hugetlbfs_inode_cache      2     35    928   35    8 : tunables    0    0    0 : slabdata      1      1      0
2145
+dquot                  0      0    640   25    4 : tunables    0    0    0 : slabdata      0      0      0
2146
+bio-1                 32     46    704   23    4 : tunables    0    0    0 : slabdata      2      2      0
2147
+eventpoll_pwq        409    600    408   20    2 : tunables    0    0    0 : slabdata     30     30      0
2148
+eventpoll_epi        408    672    576   28    4 : tunables    0    0    0 : slabdata     24     24      0
2149
+inotify_inode_mark     58    195    416   39    4 : tunables    0    0    0 : slabdata      5      5      0
2150
+scsi_data_buffer       0      0    360   22    2 : tunables    0    0    0 : slabdata      0      0      0
2151
+bio_crypt_ctx        128    147    376   21    2 : tunables    0    0    0 : slabdata      7      7      0
2152
+request_queue         29     39   2408   13    8 : tunables    0    0    0 : slabdata      3      3      0
2153
+blkdev_ioc            81    148    440   37    4 : tunables    0    0    0 : slabdata      4      4      0
2154
+bio-0                125    200    640   25    4 : tunables    0    0    0 : slabdata      8      8      0
2155
+biovec-max           166    196   4544    7    8 : tunables    0    0    0 : slabdata     28     28      0
2156
+biovec-128             0     52   2496   13    8 : tunables    0    0    0 : slabdata      4      4      0
2157
+biovec-64              0     88   1472   22    8 : tunables    0    0    0 : slabdata      4      4      0
2158
+biovec-16              0     92    704   23    4 : tunables    0    0    0 : slabdata      4      4      0
2159
+bio_integrity_payload      4     28    576   28    4 : tunables    0    0    0 : slabdata      1      1      0
2160
+khugepaged_mm_slot     59    180    448   36    4 : tunables    0    0    0 : slabdata      5      5      0
2161
+ksm_mm_slot            0      0    384   21    2 : tunables    0    0    0 : slabdata      0      0      0
2162
+ksm_stable_node        0      0    400   20    2 : tunables    0    0    0 : slabdata      0      0      0
2163
+ksm_rmap_item          0      0    400   20    2 : tunables    0    0    0 : slabdata      0      0      0
2164
+user_namespace         2     37    864   37    8 : tunables    0    0    0 : slabdata      1      1      0
2165
+uid_cache              5     28    576   28    4 : tunables    0    0    0 : slabdata      1      1      0
2166
+dmaengine-unmap-256      1     13   2496   13    8 : tunables    0    0    0 : slabdata      1      1      0
2167
+dmaengine-unmap-128      1     22   1472   22    8 : tunables    0    0    0 : slabdata      1      1      0
2168
+dmaengine-unmap-16      1     28    576   28    4 : tunables    0    0    0 : slabdata      1      1      0
2169
+dmaengine-unmap-2      1     36    448   36    4 : tunables    0    0    0 : slabdata      1      1      0
2170
+audit_buffer           0     22    360   22    2 : tunables    0    0    0 : slabdata      1      1      0
2171
+sock_inode_cache     663   1170   1216   26    8 : tunables    0    0    0 : slabdata     45     45      0
2172
+skbuff_ext_cache       0      0    576   28    4 : tunables    0    0    0 : slabdata      0      0      0
2173
+skbuff_fclone_cache      1     72    896   36    8 : tunables    0    0    0 : slabdata      2      2      0
2174
+skbuff_head_cache      3    650    640   25    4 : tunables    0    0    0 : slabdata     26     26      0
2175
+configfs_dir_cache      7     38    424   38    4 : tunables    0    0    0 : slabdata      1      1      0
2176
+file_lock_cache       27    116    552   29    4 : tunables    0    0    0 : slabdata      4      4      0
2177
+file_lock_ctx        106    120    392   20    2 : tunables    0    0    0 : slabdata      6      6      0
2178
+fsnotify_mark_connector     52     66    368   22    2 : tunables    0    0    0 : slabdata      3      3      0
2179
+net_namespace          1      6   5312    6    8 : tunables    0    0    0 : slabdata      1      1      0
2180
+task_delay_info      784   1560    416   39    4 : tunables    0    0    0 : slabdata     40     40      0
2181
+taskstats             45     92    688   23    4 : tunables    0    0    0 : slabdata      4      4      0
2182
+proc_dir_entry       678    682    528   31    4 : tunables    0    0    0 : slabdata     22     22      0
2183
+pde_opener             0    189    376   21    2 : tunables    0    0    0 : slabdata      9      9      0
2184
+proc_inode_cache    7150   8250    992   33    8 : tunables    0    0    0 : slabdata    250    250      0
2185
+seq_file              60    735    456   35    4 : tunables    0    0    0 : slabdata     21     21      0
2186
+sigqueue               0    156    416   39    4 : tunables    0    0    0 : slabdata      4      4      0
2187
+bdev_cache            36     78   1216   26    8 : tunables    0    0    0 : slabdata      3      3      0
2188
+shmem_inode_cache   1599   2208   1016   32    8 : tunables    0    0    0 : slabdata     69     69      0
2189
+kernfs_iattrs_cache   1251   1254    424   38    4 : tunables    0    0    0 : slabdata     33     33      0
2190
+kernfs_node_cache  52898  52920    464   35    4 : tunables    0    0    0 : slabdata   1512   1512      0
2191
+mnt_cache             42     46    704   23    4 : tunables    0    0    0 : slabdata      2      2      0
2192
+filp                4314   6371    704   23    4 : tunables    0    0    0 : slabdata    277    277      0
2193
+inode_cache        28695  29505    920   35    8 : tunables    0    0    0 : slabdata    843    843      0
2194
+dentry            166069 169074    528   31    4 : tunables    0    0    0 : slabdata   5454   5454      0
2195
+names_cache            0     35   4544    7    8 : tunables    0    0    0 : slabdata      5      5      0
2196
+hashtab_node           0      0    360   22    2 : tunables    0    0    0 : slabdata      0      0      0
2197
+ebitmap_node           0      0    400   20    2 : tunables    0    0    0 : slabdata      0      0      0
2198
+avtab_extended_perms      0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
2199
+avtab_node             0      0    360   22    2 : tunables    0    0    0 : slabdata      0      0      0
2200
+avc_xperms_data        0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
2201
+avc_xperms_decision_node      0      0    384   21    2 : tunables    0    0    0 : slabdata      0      0      0
2202
+avc_xperms_node        0      0    392   20    2 : tunables    0    0    0 : slabdata      0      0      0
2203
+avc_node              37     40    408   20    2 : tunables    0    0    0 : slabdata      2      2      0
2204
+iint_cache             0      0    448   36    4 : tunables    0    0    0 : slabdata      0      0      0
2205
+lsm_inode_cache   122284 122340    392   20    2 : tunables    0    0    0 : slabdata   6117   6117      0
2206
+lsm_file_cache      4266   4485    352   23    2 : tunables    0    0    0 : slabdata    195    195      0
2207
+key_jar                8     25    640   25    4 : tunables    0    0    0 : slabdata      1      1      0
2208
+buffer_head       255622 257076    440   37    4 : tunables    0    0    0 : slabdata   6948   6948      0
2209
+uts_namespace          0      0    776   21    4 : tunables    0    0    0 : slabdata      0      0      0
2210
+nsproxy               31     40    408   20    2 : tunables    0    0    0 : slabdata      2      2      0
2211
+vm_area_struct     39115  43214    528   31    4 : tunables    0    0    0 : slabdata   1394   1394      0
2212
+mm_struct             96    529   1408   23    8 : tunables    0    0    0 : slabdata     23     23      0
2213
+fs_cache             102    756    448   36    4 : tunables    0    0    0 : slabdata     21     21      0
2214
+files_cache          102    588   1152   28    8 : tunables    0    0    0 : slabdata     21     21      0
2215
+signal_cache         266    672   1536   21    8 : tunables    0    0    0 : slabdata     32     32      0
2216
+sighand_cache        266    507   2496   13    8 : tunables    0    0    0 : slabdata     39     39      0
2217
+task_struct          783    963  10240    3    8 : tunables    0    0    0 : slabdata    321    321      0
2218
+cred_jar             364    952    576   28    4 : tunables    0    0    0 : slabdata     34     34      0
2219
+anon_vma_chain     63907  67821    416   39    4 : tunables    0    0    0 : slabdata   1739   1739      0
2220
+anon_vma           25891  28899    416   39    4 : tunables    0    0    0 : slabdata    741    741      0
2221
+pid                  408    992    512   32    4 : tunables    0    0    0 : slabdata     31     31      0
2222
+Acpi-Operand        6682   6740    408   20    2 : tunables    0    0    0 : slabdata    337    337      0
2223
+Acpi-ParseExt          0     39    416   39    4 : tunables    0    0    0 : slabdata      1      1      0
2224
+Acpi-Parse             0     80    392   20    2 : tunables    0    0    0 : slabdata      4      4      0
2225
+Acpi-State             0     78    416   39    4 : tunables    0    0    0 : slabdata      2      2      0
2226
+Acpi-Namespace      3911   3948    384   21    2 : tunables    0    0    0 : slabdata    188    188      0
2227
+trace_event_file    2638   2660    424   38    4 : tunables    0    0    0 : slabdata     70     70      0
2228
+ftrace_event_field   6592   6594    384   21    2 : tunables    0    0    0 : slabdata    314    314      0
2229
+pool_workqueue        41     64   1024   32    8 : tunables    0    0    0 : slabdata      2      2      0
2230
+radix_tree_node    21638  24045    912   35    8 : tunables    0    0    0 : slabdata    687    687      0
2231
+task_group            48     78   1216   26    8 : tunables    0    0    0 : slabdata      3      3      0
2232
+vmap_area           4411   4680    400   20    2 : tunables    0    0    0 : slabdata    234    234      0
2233
+dma-kmalloc-8k         0      0  24576    1    8 : tunables    0    0    0 : slabdata      0      0      0
2234
+dma-kmalloc-4k         0      0  12288    2    8 : tunables    0    0    0 : slabdata      0      0      0
2235
+dma-kmalloc-2k         0      0   6144    5    8 : tunables    0    0    0 : slabdata      0      0      0
2236
+dma-kmalloc-1k         0      0   3072   10    8 : tunables    0    0    0 : slabdata      0      0      0
2237
+dma-kmalloc-512        0      0   1536   21    8 : tunables    0    0    0 : slabdata      0      0      0
2238
+dma-kmalloc-256        0      0   1024   32    8 : tunables    0    0    0 : slabdata      0      0      0
2239
+dma-kmalloc-128        0      0    640   25    4 : tunables    0    0    0 : slabdata      0      0      0
2240
+dma-kmalloc-64         0      0    512   32    4 : tunables    0    0    0 : slabdata      0      0      0
2241
+dma-kmalloc-32         0      0    416   39    4 : tunables    0    0    0 : slabdata      0      0      0
2242
+dma-kmalloc-16         0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
2243
+dma-kmalloc-8          0      0    344   23    2 : tunables    0    0    0 : slabdata      0      0      0
2244
+dma-kmalloc-192        0      0    528   31    4 : tunables    0    0    0 : slabdata      0      0      0
2245
+dma-kmalloc-96         0      0    432   37    4 : tunables    0    0    0 : slabdata      0      0      0
2246
+kmalloc-rcl-8k         0      0  24576    1    8 : tunables    0    0    0 : slabdata      0      0      0
2247
+kmalloc-rcl-4k         0      0  12288    2    8 : tunables    0    0    0 : slabdata      0      0      0
2248
+kmalloc-rcl-2k         0      0   6144    5    8 : tunables    0    0    0 : slabdata      0      0      0
2249
+kmalloc-rcl-1k         0      0   3072   10    8 : tunables    0    0    0 : slabdata      0      0      0
2250
+kmalloc-rcl-512        0      0   1536   21    8 : tunables    0    0    0 : slabdata      0      0      0
2251
+kmalloc-rcl-256        0      0   1024   32    8 : tunables    0    0    0 : slabdata      0      0      0
2252
+kmalloc-rcl-192        0      0    528   31    4 : tunables    0    0    0 : slabdata      0      0      0
2253
+kmalloc-rcl-128       31     75    640   25    4 : tunables    0    0    0 : slabdata      3      3      0
2254
+kmalloc-rcl-96      3371   3626    432   37    4 : tunables    0    0    0 : slabdata     98     98      0
2255
+kmalloc-rcl-64      2080   2272    512   32    4 : tunables    0    0    0 : slabdata     71     71      0
2256
+kmalloc-rcl-32         0      0    416   39    4 : tunables    0    0    0 : slabdata      0      0      0
2257
+kmalloc-rcl-16         0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
2258
+kmalloc-rcl-8          0      0    344   23    2 : tunables    0    0    0 : slabdata      0      0      0
2259
+kmalloc-8k           133    140  24576    1    8 : tunables    0    0    0 : slabdata    140    140      0
2260
+kmalloc-4k           403    444  12288    2    8 : tunables    0    0    0 : slabdata    222    222      0
2261
+kmalloc-2k          2391   2585   6144    5    8 : tunables    0    0    0 : slabdata    517    517      0
2262
+kmalloc-1k          2163   2420   3072   10    8 : tunables    0    0    0 : slabdata    242    242      0
2263
+kmalloc-512         2972   3633   1536   21    8 : tunables    0    0    0 : slabdata    173    173      0
2264
+kmalloc-256         1841   1856   1024   32    8 : tunables    0    0    0 : slabdata     58     58      0
2265
+kmalloc-192         2165   2914    528   31    4 : tunables    0    0    0 : slabdata     94     94      0
2266
+kmalloc-128         1137   1175    640   25    4 : tunables    0    0    0 : slabdata     47     47      0
2267
+kmalloc-96          1925   2590    432   37    4 : tunables    0    0    0 : slabdata     70     70      0
2268
+kmalloc-64          9433  10688    512   32    4 : tunables    0    0    0 : slabdata    334    334      0
2269
+kmalloc-32          9098  10062    416   39    4 : tunables    0    0    0 : slabdata    258    258      0
2270
+kmalloc-16         10914  10956    368   22    2 : tunables    0    0    0 : slabdata    498    498      0
2271
+kmalloc-8           7576   7705    344   23    2 : tunables    0    0    0 : slabdata    335    335      0
2272
+kmem_cache_node      904    928    512   32    4 : tunables    0    0    0 : slabdata     29     29      0
2273
+kmem_cache           904    936    832   39    8 : tunables    0    0    0 : slabdata     24     24      0
2274
+Mode: 644
2275
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1970 2276
 Path: fixtures/proc/stat
1971 2277
 Lines: 16
1972 2278
 cpu  301854 612 111922 8979004 3552 2 3944 0 0 0
... ...
@@ -2025,6 +2711,32 @@ Mode: 644
2025 2025
 Directory: fixtures/proc/sys
2026 2026
 Mode: 775
2027 2027
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2028
+Directory: fixtures/proc/sys/kernel
2029
+Mode: 775
2030
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2031
+Directory: fixtures/proc/sys/kernel/random
2032
+Mode: 755
2033
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2034
+Path: fixtures/proc/sys/kernel/random/entropy_avail
2035
+Lines: 1
2036
+3943
2037
+Mode: 644
2038
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2039
+Path: fixtures/proc/sys/kernel/random/poolsize
2040
+Lines: 1
2041
+4096
2042
+Mode: 644
2043
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2044
+Path: fixtures/proc/sys/kernel/random/urandom_min_reseed_secs
2045
+Lines: 1
2046
+60
2047
+Mode: 644
2048
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2049
+Path: fixtures/proc/sys/kernel/random/write_wakeup_threshold
2050
+Lines: 1
2051
+3072
2052
+Mode: 644
2053
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2028 2054
 Directory: fixtures/proc/sys/vm
2029 2055
 Mode: 775
2030 2056
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
... ...
@@ -2526,6 +3238,237 @@ Mode: 664
2526 2526
 Directory: fixtures/sys/block/sda
2527 2527
 Mode: 775
2528 2528
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2529
+Directory: fixtures/sys/block/sda/queue
2530
+Mode: 755
2531
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2532
+Path: fixtures/sys/block/sda/queue/add_random
2533
+Lines: 1
2534
+1
2535
+Mode: 644
2536
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2537
+Path: fixtures/sys/block/sda/queue/chunk_sectors
2538
+Lines: 1
2539
+0
2540
+Mode: 444
2541
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2542
+Path: fixtures/sys/block/sda/queue/dax
2543
+Lines: 1
2544
+0
2545
+Mode: 444
2546
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2547
+Path: fixtures/sys/block/sda/queue/discard_granularity
2548
+Lines: 1
2549
+0
2550
+Mode: 444
2551
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2552
+Path: fixtures/sys/block/sda/queue/discard_max_bytes
2553
+Lines: 1
2554
+0
2555
+Mode: 644
2556
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2557
+Path: fixtures/sys/block/sda/queue/discard_max_hw_bytes
2558
+Lines: 1
2559
+0
2560
+Mode: 444
2561
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2562
+Path: fixtures/sys/block/sda/queue/discard_zeroes_data
2563
+Lines: 1
2564
+0
2565
+Mode: 444
2566
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2567
+Path: fixtures/sys/block/sda/queue/fua
2568
+Lines: 1
2569
+0
2570
+Mode: 444
2571
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2572
+Path: fixtures/sys/block/sda/queue/hw_sector_size
2573
+Lines: 1
2574
+512
2575
+Mode: 444
2576
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2577
+Path: fixtures/sys/block/sda/queue/io_poll
2578
+Lines: 1
2579
+0
2580
+Mode: 644
2581
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2582
+Path: fixtures/sys/block/sda/queue/io_poll_delay
2583
+Lines: 1
2584
+-1
2585
+Mode: 644
2586
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2587
+Path: fixtures/sys/block/sda/queue/io_timeout
2588
+Lines: 1
2589
+30000
2590
+Mode: 644
2591
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2592
+Directory: fixtures/sys/block/sda/queue/iosched
2593
+Mode: 755
2594
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2595
+Path: fixtures/sys/block/sda/queue/iosched/back_seek_max
2596
+Lines: 1
2597
+16384
2598
+Mode: 644
2599
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2600
+Path: fixtures/sys/block/sda/queue/iosched/back_seek_penalty
2601
+Lines: 1
2602
+2
2603
+Mode: 644
2604
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2605
+Path: fixtures/sys/block/sda/queue/iosched/fifo_expire_async
2606
+Lines: 1
2607
+250
2608
+Mode: 644
2609
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2610
+Path: fixtures/sys/block/sda/queue/iosched/fifo_expire_sync
2611
+Lines: 1
2612
+125
2613
+Mode: 644
2614
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2615
+Path: fixtures/sys/block/sda/queue/iosched/low_latency
2616
+Lines: 1
2617
+1
2618
+Mode: 644
2619
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2620
+Path: fixtures/sys/block/sda/queue/iosched/max_budget
2621
+Lines: 1
2622
+0
2623
+Mode: 644
2624
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2625
+Path: fixtures/sys/block/sda/queue/iosched/slice_idle
2626
+Lines: 1
2627
+8
2628
+Mode: 644
2629
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2630
+Path: fixtures/sys/block/sda/queue/iosched/slice_idle_us
2631
+Lines: 1
2632
+8000
2633
+Mode: 644
2634
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2635
+Path: fixtures/sys/block/sda/queue/iosched/strict_guarantees
2636
+Lines: 1
2637
+0
2638
+Mode: 644
2639
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2640
+Path: fixtures/sys/block/sda/queue/iosched/timeout_sync
2641
+Lines: 1
2642
+125
2643
+Mode: 644
2644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2645
+Path: fixtures/sys/block/sda/queue/iostats
2646
+Lines: 1
2647
+1
2648
+Mode: 644
2649
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2650
+Path: fixtures/sys/block/sda/queue/logical_block_size
2651
+Lines: 1
2652
+512
2653
+Mode: 444
2654
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2655
+Path: fixtures/sys/block/sda/queue/max_discard_segments
2656
+Lines: 1
2657
+1
2658
+Mode: 444
2659
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2660
+Path: fixtures/sys/block/sda/queue/max_hw_sectors_kb
2661
+Lines: 1
2662
+32767
2663
+Mode: 444
2664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2665
+Path: fixtures/sys/block/sda/queue/max_integrity_segments
2666
+Lines: 1
2667
+0
2668
+Mode: 444
2669
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2670
+Path: fixtures/sys/block/sda/queue/max_sectors_kb
2671
+Lines: 1
2672
+1280
2673
+Mode: 644
2674
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2675
+Path: fixtures/sys/block/sda/queue/max_segment_size
2676
+Lines: 1
2677
+65536
2678
+Mode: 444
2679
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2680
+Path: fixtures/sys/block/sda/queue/max_segments
2681
+Lines: 1
2682
+168
2683
+Mode: 444
2684
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2685
+Path: fixtures/sys/block/sda/queue/minimum_io_size
2686
+Lines: 1
2687
+512
2688
+Mode: 444
2689
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2690
+Path: fixtures/sys/block/sda/queue/nomerges
2691
+Lines: 1
2692
+0
2693
+Mode: 644
2694
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2695
+Path: fixtures/sys/block/sda/queue/nr_requests
2696
+Lines: 1
2697
+64
2698
+Mode: 644
2699
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2700
+Path: fixtures/sys/block/sda/queue/nr_zones
2701
+Lines: 1
2702
+0
2703
+Mode: 444
2704
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2705
+Path: fixtures/sys/block/sda/queue/optimal_io_size
2706
+Lines: 1
2707
+0
2708
+Mode: 444
2709
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2710
+Path: fixtures/sys/block/sda/queue/physical_block_size
2711
+Lines: 1
2712
+512
2713
+Mode: 444
2714
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2715
+Path: fixtures/sys/block/sda/queue/read_ahead_kb
2716
+Lines: 1
2717
+128
2718
+Mode: 644
2719
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2720
+Path: fixtures/sys/block/sda/queue/rotational
2721
+Lines: 1
2722
+1
2723
+Mode: 644
2724
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2725
+Path: fixtures/sys/block/sda/queue/rq_affinity
2726
+Lines: 1
2727
+1
2728
+Mode: 644
2729
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2730
+Path: fixtures/sys/block/sda/queue/scheduler
2731
+Lines: 1
2732
+mq-deadline kyber [bfq] none
2733
+Mode: 644
2734
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2735
+Path: fixtures/sys/block/sda/queue/wbt_lat_usec
2736
+Lines: 1
2737
+75000
2738
+Mode: 644
2739
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2740
+Path: fixtures/sys/block/sda/queue/write_cache
2741
+Lines: 1
2742
+write back
2743
+Mode: 644
2744
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2745
+Path: fixtures/sys/block/sda/queue/write_same_max_bytes
2746
+Lines: 1
2747
+0
2748
+Mode: 444
2749
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2750
+Path: fixtures/sys/block/sda/queue/write_zeroes_max_bytes
2751
+Lines: 1
2752
+0
2753
+Mode: 444
2754
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2755
+Path: fixtures/sys/block/sda/queue/zoned
2756
+Lines: 1
2757
+none
2758
+Mode: 444
2759
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2529 2760
 Path: fixtures/sys/block/sda/stat
2530 2761
 Lines: 1
2531 2762
 9652963   396792 759304206   412943  8422549  6731723 286915323 13947418        0  5658367 19174573 1 2 3 12
... ...
@@ -2534,9 +3477,719 @@ Mode: 664
2534 2534
 Directory: fixtures/sys/class
2535 2535
 Mode: 775
2536 2536
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2537
+Directory: fixtures/sys/class/drm
2538
+Mode: 755
2539
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2540
+Directory: fixtures/sys/class/drm/card0
2541
+Mode: 755
2542
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2543
+Directory: fixtures/sys/class/drm/card0/device
2544
+Mode: 755
2545
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2546
+Path: fixtures/sys/class/drm/card0/device/aer_dev_correctable
2547
+Lines: 9
2548
+RxErr 0
2549
+BadTLP 0
2550
+BadDLLP 0
2551
+Rollover 0
2552
+Timeout 0
2553
+NonFatalErr 0
2554
+CorrIntErr 0
2555
+HeaderOF 0
2556
+TOTAL_ERR_COR 0
2557
+Mode: 444
2558
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2559
+Path: fixtures/sys/class/drm/card0/device/aer_dev_fatal
2560
+Lines: 19
2561
+Undefined 0
2562
+DLP 0
2563
+SDES 0
2564
+TLP 0
2565
+FCP 0
2566
+CmpltTO 0
2567
+CmpltAbrt 0
2568
+UnxCmplt 0
2569
+RxOF 0
2570
+MalfTLP 0
2571
+ECRC 0
2572
+UnsupReq 0
2573
+ACSViol 0
2574
+UncorrIntErr 0
2575
+BlockedTLP 0
2576
+AtomicOpBlocked 0
2577
+TLPBlockedErr 0
2578
+PoisonTLPBlocked 0
2579
+TOTAL_ERR_FATAL 0
2580
+Mode: 444
2581
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2582
+Path: fixtures/sys/class/drm/card0/device/aer_dev_nonfatal
2583
+Lines: 19
2584
+Undefined 0
2585
+DLP 0
2586
+SDES 0
2587
+TLP 0
2588
+FCP 0
2589
+CmpltTO 0
2590
+CmpltAbrt 0
2591
+UnxCmplt 0
2592
+RxOF 0
2593
+MalfTLP 0
2594
+ECRC 0
2595
+UnsupReq 0
2596
+ACSViol 0
2597
+UncorrIntErr 0
2598
+BlockedTLP 0
2599
+AtomicOpBlocked 0
2600
+TLPBlockedErr 0
2601
+PoisonTLPBlocked 0
2602
+TOTAL_ERR_NONFATAL 0
2603
+Mode: 444
2604
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2605
+Path: fixtures/sys/class/drm/card0/device/ari_enabled
2606
+Lines: 1
2607
+0
2608
+Mode: 444
2609
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2610
+Path: fixtures/sys/class/drm/card0/device/boot_vga
2611
+Lines: 1
2612
+1
2613
+Mode: 444
2614
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2615
+Path: fixtures/sys/class/drm/card0/device/broken_parity_status
2616
+Lines: 1
2617
+0
2618
+Mode: 644
2619
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2620
+Path: fixtures/sys/class/drm/card0/device/class
2621
+Lines: 1
2622
+0x030000
2623
+Mode: 444
2624
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2625
+Path: fixtures/sys/class/drm/card0/device/consistent_dma_mask_bits
2626
+Lines: 1
2627
+44
2628
+Mode: 444
2629
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2630
+Path: fixtures/sys/class/drm/card0/device/current_link_speed
2631
+Lines: 1
2632
+8.0 GT/s PCIe
2633
+Mode: 444
2634
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2635
+Path: fixtures/sys/class/drm/card0/device/current_link_width
2636
+Lines: 1
2637
+16
2638
+Mode: 444
2639
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2640
+Path: fixtures/sys/class/drm/card0/device/d3cold_allowed
2641
+Lines: 1
2642
+1
2643
+Mode: 644
2644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2645
+Path: fixtures/sys/class/drm/card0/device/device
2646
+Lines: 1
2647
+0x687f
2648
+Mode: 444
2649
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2650
+Path: fixtures/sys/class/drm/card0/device/dma_mask_bits
2651
+Lines: 1
2652
+44
2653
+Mode: 444
2654
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2655
+Path: fixtures/sys/class/drm/card0/device/driver_override
2656
+Lines: 1
2657
+(null)
2658
+Mode: 644
2659
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2660
+Path: fixtures/sys/class/drm/card0/device/enable
2661
+Lines: 1
2662
+1
2663
+Mode: 644
2664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2665
+Path: fixtures/sys/class/drm/card0/device/gpu_busy_percent
2666
+Lines: 1
2667
+4
2668
+Mode: 444
2669
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2670
+Path: fixtures/sys/class/drm/card0/device/irq
2671
+Lines: 1
2672
+95
2673
+Mode: 444
2674
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2675
+Path: fixtures/sys/class/drm/card0/device/local_cpulist
2676
+Lines: 1
2677
+0-15
2678
+Mode: 444
2679
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2680
+Path: fixtures/sys/class/drm/card0/device/local_cpus
2681
+Lines: 1
2682
+0000ffff
2683
+Mode: 444
2684
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2685
+Path: fixtures/sys/class/drm/card0/device/max_link_speed
2686
+Lines: 1
2687
+8.0 GT/s PCIe
2688
+Mode: 444
2689
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2690
+Path: fixtures/sys/class/drm/card0/device/max_link_width
2691
+Lines: 1
2692
+16
2693
+Mode: 444
2694
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2695
+Path: fixtures/sys/class/drm/card0/device/mem_info_gtt_total
2696
+Lines: 1
2697
+8573157376
2698
+Mode: 444
2699
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2700
+Path: fixtures/sys/class/drm/card0/device/mem_info_gtt_used
2701
+Lines: 1
2702
+144560128
2703
+Mode: 444
2704
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2705
+Path: fixtures/sys/class/drm/card0/device/mem_info_vis_vram_total
2706
+Lines: 1
2707
+8573157376
2708
+Mode: 444
2709
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2710
+Path: fixtures/sys/class/drm/card0/device/mem_info_vis_vram_used
2711
+Lines: 1
2712
+1490378752
2713
+Mode: 444
2714
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2715
+Path: fixtures/sys/class/drm/card0/device/mem_info_vram_total
2716
+Lines: 1
2717
+8573157376
2718
+Mode: 444
2719
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2720
+Path: fixtures/sys/class/drm/card0/device/mem_info_vram_used
2721
+Lines: 1
2722
+1490378752
2723
+Mode: 444
2724
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2725
+Path: fixtures/sys/class/drm/card0/device/mem_info_vram_vendor
2726
+Lines: 1
2727
+samsung
2728
+Mode: 444
2729
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2730
+Path: fixtures/sys/class/drm/card0/device/modalias
2731
+Lines: 1
2732
+pci:v00001002d0000687Fsv00001043sd000004C4bc03sc00i00
2733
+Mode: 444
2734
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2735
+Path: fixtures/sys/class/drm/card0/device/msi_bus
2736
+Lines: 1
2737
+1
2738
+Mode: 644
2739
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2740
+Path: fixtures/sys/class/drm/card0/device/numa_node
2741
+Lines: 1
2742
+-1
2743
+Mode: 644
2744
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2745
+Path: fixtures/sys/class/drm/card0/device/pcie_bw
2746
+Lines: 1
2747
+6641 815 256
2748
+Mode: 444
2749
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2750
+Path: fixtures/sys/class/drm/card0/device/pcie_replay_count
2751
+Lines: 1
2752
+0
2753
+Mode: 444
2754
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2755
+Path: fixtures/sys/class/drm/card0/device/power_dpm_force_performance_level
2756
+Lines: 1
2757
+manual
2758
+Mode: 644
2759
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2760
+Path: fixtures/sys/class/drm/card0/device/power_dpm_state
2761
+Lines: 1
2762
+performance
2763
+Mode: 644
2764
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2765
+Path: fixtures/sys/class/drm/card0/device/power_state
2766
+Lines: 1
2767
+D0
2768
+Mode: 444
2769
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2770
+Path: fixtures/sys/class/drm/card0/device/pp_cur_state
2771
+Lines: 1
2772
+1
2773
+Mode: 444
2774
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2775
+Path: fixtures/sys/class/drm/card0/device/pp_dpm_dcefclk
2776
+Lines: 5
2777
+0: 600Mhz *
2778
+1: 720Mhz 
2779
+2: 800Mhz 
2780
+3: 847Mhz 
2781
+4: 900Mhz 
2782
+Mode: 644
2783
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2784
+Path: fixtures/sys/class/drm/card0/device/pp_dpm_mclk
2785
+Lines: 4
2786
+0: 167Mhz *
2787
+1: 500Mhz 
2788
+2: 800Mhz 
2789
+3: 945Mhz 
2790
+Mode: 644
2791
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2792
+Path: fixtures/sys/class/drm/card0/device/pp_dpm_pcie
2793
+Lines: 2
2794
+0: 8.0GT/s, x16 
2795
+1: 8.0GT/s, x16 *
2796
+Mode: 644
2797
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2798
+Path: fixtures/sys/class/drm/card0/device/pp_dpm_sclk
2799
+Lines: 8
2800
+0: 852Mhz *
2801
+1: 991Mhz 
2802
+2: 1084Mhz 
2803
+3: 1138Mhz 
2804
+4: 1200Mhz 
2805
+5: 1401Mhz 
2806
+6: 1536Mhz 
2807
+7: 1630Mhz 
2808
+Mode: 644
2809
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2810
+Path: fixtures/sys/class/drm/card0/device/pp_dpm_socclk
2811
+Lines: 8
2812
+0: 600Mhz 
2813
+1: 720Mhz *
2814
+2: 800Mhz 
2815
+3: 847Mhz 
2816
+4: 900Mhz 
2817
+5: 960Mhz 
2818
+6: 1028Mhz 
2819
+7: 1107Mhz 
2820
+Mode: 644
2821
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2822
+Path: fixtures/sys/class/drm/card0/device/pp_features
2823
+Lines: 32
2824
+Current ppfeatures: 0x0000000019a1ff4f
2825
+FEATURES            BITMASK                ENABLEMENT
2826
+DPM_PREFETCHER      0x0000000000000001      Y
2827
+GFXCLK_DPM          0x0000000000000002      Y
2828
+UCLK_DPM            0x0000000000000004      Y
2829
+SOCCLK_DPM          0x0000000000000008      Y
2830
+UVD_DPM             0x0000000000000010      N
2831
+VCE_DPM             0x0000000000000020      N
2832
+ULV                 0x0000000000000040      Y
2833
+MP0CLK_DPM          0x0000000000000080      N
2834
+LINK_DPM            0x0000000000000100      Y
2835
+DCEFCLK_DPM         0x0000000000000200      Y
2836
+AVFS                0x0000000000000400      Y
2837
+GFXCLK_DS           0x0000000000000800      Y
2838
+SOCCLK_DS           0x0000000000001000      Y
2839
+LCLK_DS             0x0000000000002000      Y
2840
+PPT                 0x0000000000004000      Y
2841
+TDC                 0x0000000000008000      Y
2842
+THERMAL             0x0000000000010000      Y
2843
+GFX_PER_CU_CG       0x0000000000020000      N
2844
+RM                  0x0000000000040000      N
2845
+DCEFCLK_DS          0x0000000000080000      N
2846
+ACDC                0x0000000000100000      N
2847
+VR0HOT              0x0000000000200000      Y
2848
+VR1HOT              0x0000000000400000      N
2849
+FW_CTF              0x0000000000800000      Y
2850
+LED_DISPLAY         0x0000000001000000      Y
2851
+FAN_CONTROL         0x0000000002000000      N
2852
+FAST_PPT            0x0000000004000000      N
2853
+DIDT                0x0000000008000000      Y
2854
+ACG                 0x0000000010000000      Y
2855
+PCC_LIMIT           0x0000000020000000      N
2856
+Mode: 644
2857
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2858
+Path: fixtures/sys/class/drm/card0/device/pp_force_state
2859
+Lines: 1
2860
+
2861
+Mode: 644
2862
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2863
+Path: fixtures/sys/class/drm/card0/device/pp_mclk_od
2864
+Lines: 1
2865
+0
2866
+Mode: 644
2867
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2868
+Path: fixtures/sys/class/drm/card0/device/pp_num_states
2869
+Lines: 3
2870
+states: 2
2871
+0 boot
2872
+1 performance
2873
+Mode: 444
2874
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2875
+Path: fixtures/sys/class/drm/card0/device/pp_od_clk_voltage
2876
+Lines: 18
2877
+OD_SCLK:
2878
+0:        852Mhz        800mV
2879
+1:        991Mhz        900mV
2880
+2:       1084Mhz        950mV
2881
+3:       1138Mhz       1000mV
2882
+4:       1200Mhz       1050mV
2883
+5:       1401Mhz       1100mV
2884
+6:       1536Mhz       1150mV
2885
+7:       1630Mhz       1200mV
2886
+OD_MCLK:
2887
+0:        167Mhz        800mV
2888
+1:        500Mhz        800mV
2889
+2:        800Mhz        950mV
2890
+3:        945Mhz       1100mV
2891
+OD_RANGE:
2892
+SCLK:     852MHz       2400MHz
2893
+MCLK:     167MHz       1500MHz
2894
+VDDC:     800mV        1200mV
2895
+Mode: 644
2896
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2897
+Path: fixtures/sys/class/drm/card0/device/pp_power_profile_mode
2898
+Lines: 8
2899
+NUM        MODE_NAME BUSY_SET_POINT FPS USE_RLC_BUSY MIN_ACTIVE_LEVEL
2900
+  0 BOOTUP_DEFAULT :             70  60          0              0
2901
+  1 3D_FULL_SCREEN*:             70  60          1              3
2902
+  2   POWER_SAVING :             90  60          0              0
2903
+  3          VIDEO :             70  60          0              0
2904
+  4             VR :             70  90          0              0
2905
+  5        COMPUTE :             30  60          0              6
2906
+  6         CUSTOM :              0   0          0              0
2907
+Mode: 644
2908
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2909
+Path: fixtures/sys/class/drm/card0/device/pp_sclk_od
2910
+Lines: 1
2911
+0
2912
+Mode: 644
2913
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2914
+Path: fixtures/sys/class/drm/card0/device/product_name
2915
+Lines: 1
2916
+
2917
+Mode: 444
2918
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2919
+Path: fixtures/sys/class/drm/card0/device/product_number
2920
+Lines: 1
2921
+
2922
+Mode: 444
2923
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2924
+Path: fixtures/sys/class/drm/card0/device/resource
2925
+Lines: 13
2926
+0x0000007c00000000 0x0000007dffffffff 0x000000000014220c
2927
+0x0000000000000000 0x0000000000000000 0x0000000000000000
2928
+0x0000007e00000000 0x0000007e0fffffff 0x000000000014220c
2929
+0x0000000000000000 0x0000000000000000 0x0000000000000000
2930
+0x000000000000d000 0x000000000000d0ff 0x0000000000040101
2931
+0x00000000fcd00000 0x00000000fcd7ffff 0x0000000000040200
2932
+0x00000000fcd80000 0x00000000fcd9ffff 0x0000000000046200
2933
+0x0000000000000000 0x0000000000000000 0x0000000000000000
2934
+0x0000000000000000 0x0000000000000000 0x0000000000000000
2935
+0x0000000000000000 0x0000000000000000 0x0000000000000000
2936
+0x0000000000000000 0x0000000000000000 0x0000000000000000
2937
+0x0000000000000000 0x0000000000000000 0x0000000000000000
2938
+0x0000000000000000 0x0000000000000000 0x0000000000000000
2939
+Mode: 444
2940
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2941
+Path: fixtures/sys/class/drm/card0/device/revision
2942
+Lines: 1
2943
+0xc1
2944
+Mode: 444
2945
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2946
+Path: fixtures/sys/class/drm/card0/device/serial_number
2947
+Lines: 1
2948
+
2949
+Mode: 444
2950
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2951
+Path: fixtures/sys/class/drm/card0/device/subsystem_device
2952
+Lines: 1
2953
+0x04c4
2954
+Mode: 444
2955
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2956
+Path: fixtures/sys/class/drm/card0/device/subsystem_vendor
2957
+Lines: 1
2958
+0x1043
2959
+Mode: 444
2960
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2961
+Path: fixtures/sys/class/drm/card0/device/thermal_throttling_logging
2962
+Lines: 1
2963
+0000:09:00.0: thermal throttling logging enabled, with interval 60 seconds
2964
+Mode: 644
2965
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2966
+Path: fixtures/sys/class/drm/card0/device/uevent
2967
+Lines: 6
2968
+DRIVER=amdgpu
2969
+PCI_CLASS=30000
2970
+PCI_ID=1002:687F
2971
+PCI_SUBSYS_ID=1043:04C4
2972
+PCI_SLOT_NAME=0000:09:00.0
2973
+MODALIAS=pci:v00001002d0000687Fsv00001043sd000004C4bc03sc00i00
2974
+Mode: 644
2975
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2976
+Path: fixtures/sys/class/drm/card0/device/unique_id
2977
+Lines: 1
2978
+0123456789abcdef
2979
+Mode: 444
2980
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2981
+Path: fixtures/sys/class/drm/card0/device/vbios_version
2982
+Lines: 1
2983
+115-D050PIL-100
2984
+Mode: 444
2985
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2986
+Path: fixtures/sys/class/drm/card0/device/vendor
2987
+Lines: 1
2988
+0x1002
2989
+Mode: 444
2990
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2991
+Directory: fixtures/sys/class/fc_host
2992
+Mode: 755
2993
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2994
+Directory: fixtures/sys/class/fc_host/host0
2995
+Mode: 755
2996
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2997
+Path: fixtures/sys/class/fc_host/host0/dev_loss_tmo
2998
+Lines: 1
2999
+30
3000
+Mode: 644
3001
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3002
+Path: fixtures/sys/class/fc_host/host0/fabric_name
3003
+Lines: 1
3004
+0x0
3005
+Mode: 644
3006
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3007
+Path: fixtures/sys/class/fc_host/host0/node_name
3008
+Lines: 1
3009
+0x2000e0071bce95f2
3010
+Mode: 644
3011
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3012
+Path: fixtures/sys/class/fc_host/host0/port_id
3013
+Lines: 1
3014
+0x000002
3015
+Mode: 644
3016
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3017
+Path: fixtures/sys/class/fc_host/host0/port_name
3018
+Lines: 1
3019
+0x1000e0071bce95f2
3020
+Mode: 644
3021
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3022
+Path: fixtures/sys/class/fc_host/host0/port_state
3023
+Lines: 1
3024
+Online
3025
+Mode: 644
3026
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3027
+Path: fixtures/sys/class/fc_host/host0/port_type
3028
+Lines: 1
3029
+Point-To-Point (direct nport connection)
3030
+Mode: 644
3031
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3032
+Path: fixtures/sys/class/fc_host/host0/speed
3033
+Lines: 1
3034
+16 Gbit
3035
+Mode: 644
3036
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3037
+Directory: fixtures/sys/class/fc_host/host0/statistics
3038
+Mode: 755
3039
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3040
+Path: fixtures/sys/class/fc_host/host0/statistics/dumped_frames
3041
+Lines: 1
3042
+0xffffffffffffffff
3043
+Mode: 644
3044
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3045
+Path: fixtures/sys/class/fc_host/host0/statistics/error_frames
3046
+Lines: 1
3047
+0x0
3048
+Mode: 644
3049
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3050
+Path: fixtures/sys/class/fc_host/host0/statistics/fcp_packet_aborts
3051
+Lines: 1
3052
+0x13
3053
+Mode: 644
3054
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3055
+Path: fixtures/sys/class/fc_host/host0/statistics/invalid_crc_count
3056
+Lines: 1
3057
+0x2
3058
+Mode: 644
3059
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3060
+Path: fixtures/sys/class/fc_host/host0/statistics/invalid_tx_word_count
3061
+Lines: 1
3062
+0x8
3063
+Mode: 644
3064
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3065
+Path: fixtures/sys/class/fc_host/host0/statistics/link_failure_count
3066
+Lines: 1
3067
+0x9
3068
+Mode: 644
3069
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3070
+Path: fixtures/sys/class/fc_host/host0/statistics/loss_of_signal_count
3071
+Lines: 1
3072
+0x11
3073
+Mode: 644
3074
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3075
+Path: fixtures/sys/class/fc_host/host0/statistics/loss_of_sync_count
3076
+Lines: 1
3077
+0x10
3078
+Mode: 644
3079
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3080
+Path: fixtures/sys/class/fc_host/host0/statistics/nos_count
3081
+Lines: 1
3082
+0x12
3083
+Mode: 644
3084
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3085
+Path: fixtures/sys/class/fc_host/host0/statistics/rx_frames
3086
+Lines: 1
3087
+0x3
3088
+Mode: 644
3089
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3090
+Path: fixtures/sys/class/fc_host/host0/statistics/rx_words
3091
+Lines: 1
3092
+0x4
3093
+Mode: 644
3094
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3095
+Path: fixtures/sys/class/fc_host/host0/statistics/seconds_since_last_reset
3096
+Lines: 1
3097
+0x7
3098
+Mode: 644
3099
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3100
+Path: fixtures/sys/class/fc_host/host0/statistics/tx_frames
3101
+Lines: 1
3102
+0x5
3103
+Mode: 644
3104
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3105
+Path: fixtures/sys/class/fc_host/host0/statistics/tx_words
3106
+Lines: 1
3107
+0x6
3108
+Mode: 644
3109
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3110
+Path: fixtures/sys/class/fc_host/host0/supported_classes
3111
+Lines: 1
3112
+Class 3
3113
+Mode: 644
3114
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3115
+Path: fixtures/sys/class/fc_host/host0/supported_speeds
3116
+Lines: 1
3117
+4 Gbit, 8 Gbit, 16 Gbit
3118
+Mode: 644
3119
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3120
+Path: fixtures/sys/class/fc_host/host0/symbolic_name
3121
+Lines: 1
3122
+Emulex SN1100E2P FV12.4.270.3 DV12.4.0.0. HN:gotest. OS:Linux
3123
+Mode: 644
3124
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2537 3125
 Directory: fixtures/sys/class/infiniband
2538 3126
 Mode: 755
2539 3127
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3128
+Directory: fixtures/sys/class/infiniband/hfi1_0
3129
+Mode: 755
3130
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3131
+Path: fixtures/sys/class/infiniband/hfi1_0/board_id
3132
+Lines: 1
3133
+HPE 100Gb 1-port OP101 QSFP28 x16 PCIe Gen3 with Intel Omni-Path Adapter
3134
+Mode: 644
3135
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3136
+Path: fixtures/sys/class/infiniband/hfi1_0/fw_ver
3137
+Lines: 1
3138
+1.27.0
3139
+Mode: 644
3140
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3141
+Directory: fixtures/sys/class/infiniband/hfi1_0/ports
3142
+Mode: 755
3143
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3144
+Directory: fixtures/sys/class/infiniband/hfi1_0/ports/1
3145
+Mode: 755
3146
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3147
+Directory: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters
3148
+Mode: 755
3149
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3150
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/VL15_dropped
3151
+Lines: 1
3152
+0
3153
+Mode: 644
3154
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3155
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/excessive_buffer_overrun_errors
3156
+Lines: 1
3157
+0
3158
+Mode: 644
3159
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3160
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/link_downed
3161
+Lines: 1
3162
+0
3163
+Mode: 644
3164
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3165
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/link_error_recovery
3166
+Lines: 1
3167
+0
3168
+Mode: 644
3169
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3170
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/local_link_integrity_errors
3171
+Lines: 1
3172
+0
3173
+Mode: 644
3174
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3175
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_constraint_errors
3176
+Lines: 1
3177
+0
3178
+Mode: 644
3179
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3180
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_data
3181
+Lines: 1
3182
+345091702026
3183
+Mode: 644
3184
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3185
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_errors
3186
+Lines: 1
3187
+0
3188
+Mode: 644
3189
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3190
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_packets
3191
+Lines: 1
3192
+638036947
3193
+Mode: 644
3194
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3195
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_remote_physical_errors
3196
+Lines: 1
3197
+0
3198
+Mode: 644
3199
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3200
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_switch_relay_errors
3201
+Lines: 1
3202
+0
3203
+Mode: 644
3204
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3205
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_xmit_constraint_errors
3206
+Lines: 1
3207
+0
3208
+Mode: 644
3209
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3210
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_xmit_data
3211
+Lines: 1
3212
+273558326543
3213
+Mode: 644
3214
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3215
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_xmit_discards
3216
+Lines: 1
3217
+0
3218
+Mode: 644
3219
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3220
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_xmit_packets
3221
+Lines: 1
3222
+568318856
3223
+Mode: 644
3224
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3225
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_xmit_wait
3226
+Lines: 1
3227
+0
3228
+Mode: 644
3229
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3230
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/symbol_error
3231
+Lines: 1
3232
+0
3233
+Mode: 644
3234
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3235
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/phys_state
3236
+Lines: 1
3237
+5: LinkUp
3238
+Mode: 644
3239
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3240
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/rate
3241
+Lines: 1
3242
+100 Gb/sec (4X EDR)
3243
+Mode: 644
3244
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3245
+Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/state
3246
+Lines: 1
3247
+4: ACTIVE
3248
+Mode: 644
3249
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2540 3250
 Directory: fixtures/sys/class/infiniband/mlx4_0
2541 3251
 Mode: 755
2542 3252
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
... ...
@@ -2564,6 +4217,11 @@ Mode: 755
2564 2564
 Directory: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters
2565 2565
 Mode: 755
2566 2566
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2567
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/VL15_dropped
2568
+Lines: 1
2569
+0
2570
+Mode: 664
2571
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2567 2572
 Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/excessive_buffer_overrun_errors
2568 2573
 Lines: 1
2569 2574
 0
... ...
@@ -2665,6 +4323,11 @@ Mode: 755
2665 2665
 Directory: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters
2666 2666
 Mode: 755
2667 2667
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2668
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/VL15_dropped
2669
+Lines: 1
2670
+0
2671
+Mode: 664
2672
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2668 2673
 Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/excessive_buffer_overrun_errors
2669 2674
 Lines: 1
2670 2675
 0
... ...
@@ -2895,6 +4558,32 @@ Lines: 1
2895 2895
 1
2896 2896
 Mode: 644
2897 2897
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2898
+Directory: fixtures/sys/class/nvme
2899
+Mode: 775
2900
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2901
+Directory: fixtures/sys/class/nvme/nvme0
2902
+Mode: 775
2903
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2904
+Path: fixtures/sys/class/nvme/nvme0/firmware_rev
2905
+Lines: 1
2906
+1B2QEXP7
2907
+Mode: 664
2908
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2909
+Path: fixtures/sys/class/nvme/nvme0/model
2910
+Lines: 1
2911
+Samsung SSD 970 PRO 512GB               
2912
+Mode: 664
2913
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2914
+Path: fixtures/sys/class/nvme/nvme0/serial
2915
+Lines: 1
2916
+S680HF8N190894I
2917
+Mode: 664
2918
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2919
+Path: fixtures/sys/class/nvme/nvme0/state
2920
+Lines: 1
2921
+live
2922
+Mode: 664
2923
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2898 2924
 Directory: fixtures/sys/class/power_supply
2899 2925
 Mode: 755
2900 2926
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
... ...
@@ -3032,6 +4721,100 @@ Path: fixtures/sys/class/powercap/intel-rapl:0:0/uevent
3032 3032
 Lines: 0
3033 3033
 Mode: 644
3034 3034
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3035
+Directory: fixtures/sys/class/powercap/intel-rapl:a
3036
+Mode: 755
3037
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3038
+Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_0_max_power_uw
3039
+Lines: 1
3040
+95000000
3041
+Mode: 444
3042
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3043
+Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_0_name
3044
+Lines: 1
3045
+long_term
3046
+Mode: 444
3047
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3048
+Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_0_power_limit_uw
3049
+Lines: 1
3050
+4090000000
3051
+Mode: 644
3052
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3053
+Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_0_time_window_us
3054
+Lines: 1
3055
+999424
3056
+Mode: 644
3057
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3058
+Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_1_max_power_uw
3059
+Lines: 1
3060
+0
3061
+Mode: 444
3062
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3063
+Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_1_name
3064
+Lines: 1
3065
+short_term
3066
+Mode: 444
3067
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3068
+Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_1_power_limit_uw
3069
+Lines: 1
3070
+4090000000
3071
+Mode: 644
3072
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3073
+Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_1_time_window_us
3074
+Lines: 1
3075
+2440
3076
+Mode: 644
3077
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3078
+Path: fixtures/sys/class/powercap/intel-rapl:a/enabled
3079
+Lines: 1
3080
+1
3081
+Mode: 644
3082
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3083
+Path: fixtures/sys/class/powercap/intel-rapl:a/energy_uj
3084
+Lines: 1
3085
+240422366267
3086
+Mode: 444
3087
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3088
+Path: fixtures/sys/class/powercap/intel-rapl:a/max_energy_range_uj
3089
+Lines: 1
3090
+262143328850
3091
+Mode: 444
3092
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3093
+Path: fixtures/sys/class/powercap/intel-rapl:a/name
3094
+Lines: 1
3095
+package-10
3096
+Mode: 444
3097
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3098
+Path: fixtures/sys/class/powercap/intel-rapl:a/uevent
3099
+Lines: 0
3100
+Mode: 644
3101
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3102
+Directory: fixtures/sys/class/scsi_tape
3103
+Mode: 755
3104
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3105
+Path: fixtures/sys/class/scsi_tape/nst0
3106
+SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0
3107
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3108
+Path: fixtures/sys/class/scsi_tape/nst0a
3109
+SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a
3110
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3111
+Path: fixtures/sys/class/scsi_tape/nst0l
3112
+SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l
3113
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3114
+Path: fixtures/sys/class/scsi_tape/nst0m
3115
+SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m
3116
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3117
+Path: fixtures/sys/class/scsi_tape/st0
3118
+SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0
3119
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3120
+Path: fixtures/sys/class/scsi_tape/st0a
3121
+SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a
3122
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3123
+Path: fixtures/sys/class/scsi_tape/st0l
3124
+SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l
3125
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3126
+Path: fixtures/sys/class/scsi_tape/st0m
3127
+SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m
3128
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3035 3129
 Directory: fixtures/sys/class/thermal
3036 3130
 Mode: 775
3037 3131
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
... ...
@@ -3109,7 +4892,7 @@ Mode: 664
3109 3109
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3110 3110
 Path: fixtures/sys/class/thermal/thermal_zone1/temp
3111 3111
 Lines: 1
3112
-44000
3112
+-44000
3113 3113
 Mode: 664
3114 3114
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3115 3115
 Path: fixtures/sys/class/thermal/thermal_zone1/type
... ...
@@ -3443,6 +5226,475 @@ Mode: 444
3443 3443
 Directory: fixtures/sys/devices/pci0000:00
3444 3444
 Mode: 755
3445 3445
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3446
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0
3447
+Mode: 755
3448
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3449
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0
3450
+Mode: 755
3451
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3452
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0
3453
+Mode: 755
3454
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3455
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0
3456
+Mode: 755
3457
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3458
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0
3459
+Mode: 755
3460
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3461
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0
3462
+Mode: 755
3463
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3464
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape
3465
+Mode: 755
3466
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3467
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0
3468
+Mode: 755
3469
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3470
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats
3471
+Mode: 755
3472
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3473
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/in_flight
3474
+Lines: 1
3475
+1EOF
3476
+Mode: 444
3477
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3478
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/io_ns
3479
+Lines: 1
3480
+9247011087720EOF
3481
+Mode: 444
3482
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3483
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/other_cnt
3484
+Lines: 1
3485
+1409EOF
3486
+Mode: 444
3487
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3488
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/read_byte_cnt
3489
+Lines: 1
3490
+979383912EOF
3491
+Mode: 444
3492
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3493
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/read_cnt
3494
+Lines: 1
3495
+3741EOF
3496
+Mode: 444
3497
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3498
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/read_ns
3499
+Lines: 1
3500
+33788355744EOF
3501
+Mode: 444
3502
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3503
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/resid_cnt
3504
+Lines: 1
3505
+19EOF
3506
+Mode: 444
3507
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3508
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/write_byte_cnt
3509
+Lines: 1
3510
+1496246784000EOF
3511
+Mode: 444
3512
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3513
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/write_cnt
3514
+Lines: 1
3515
+53772916EOF
3516
+Mode: 444
3517
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3518
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/write_ns
3519
+Lines: 1
3520
+5233597394395EOF
3521
+Mode: 444
3522
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3523
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a
3524
+Mode: 755
3525
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3526
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats
3527
+Mode: 755
3528
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3529
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/in_flight
3530
+Lines: 1
3531
+1EOF
3532
+Mode: 444
3533
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3534
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/io_ns
3535
+Lines: 1
3536
+9247011087720EOF
3537
+Mode: 444
3538
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3539
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/other_cnt
3540
+Lines: 1
3541
+1409EOF
3542
+Mode: 444
3543
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3544
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/read_byte_cnt
3545
+Lines: 1
3546
+979383912EOF
3547
+Mode: 444
3548
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3549
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/read_cnt
3550
+Lines: 1
3551
+3741EOF
3552
+Mode: 444
3553
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3554
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/read_ns
3555
+Lines: 1
3556
+33788355744EOF
3557
+Mode: 444
3558
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3559
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/resid_cnt
3560
+Lines: 1
3561
+19EOF
3562
+Mode: 444
3563
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3564
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/write_byte_cnt
3565
+Lines: 1
3566
+1496246784000EOF
3567
+Mode: 444
3568
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3569
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/write_cnt
3570
+Lines: 1
3571
+53772916EOF
3572
+Mode: 444
3573
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3574
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/write_ns
3575
+Lines: 1
3576
+5233597394395EOF
3577
+Mode: 444
3578
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3579
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l
3580
+Mode: 755
3581
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3582
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats
3583
+Mode: 755
3584
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3585
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/in_flight
3586
+Lines: 1
3587
+1EOF
3588
+Mode: 444
3589
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3590
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/io_ns
3591
+Lines: 1
3592
+9247011087720EOF
3593
+Mode: 444
3594
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3595
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/other_cnt
3596
+Lines: 1
3597
+1409EOF
3598
+Mode: 444
3599
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3600
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/read_byte_cnt
3601
+Lines: 1
3602
+979383912EOF
3603
+Mode: 444
3604
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3605
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/read_cnt
3606
+Lines: 1
3607
+3741EOF
3608
+Mode: 444
3609
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3610
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/read_ns
3611
+Lines: 1
3612
+33788355744EOF
3613
+Mode: 444
3614
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3615
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/resid_cnt
3616
+Lines: 1
3617
+19EOF
3618
+Mode: 444
3619
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3620
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/write_byte_cnt
3621
+Lines: 1
3622
+1496246784000EOF
3623
+Mode: 444
3624
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3625
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/write_cnt
3626
+Lines: 1
3627
+53772916EOF
3628
+Mode: 444
3629
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3630
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/write_ns
3631
+Lines: 1
3632
+5233597394395EOF
3633
+Mode: 444
3634
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3635
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m
3636
+Mode: 755
3637
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3638
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats
3639
+Mode: 755
3640
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3641
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/in_flight
3642
+Lines: 1
3643
+1EOF
3644
+Mode: 444
3645
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3646
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/io_ns
3647
+Lines: 1
3648
+9247011087720EOF
3649
+Mode: 444
3650
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3651
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/other_cnt
3652
+Lines: 1
3653
+1409EOF
3654
+Mode: 444
3655
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3656
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/read_byte_cnt
3657
+Lines: 1
3658
+979383912EOF
3659
+Mode: 444
3660
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3661
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/read_cnt
3662
+Lines: 1
3663
+3741EOF
3664
+Mode: 444
3665
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3666
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/read_ns
3667
+Lines: 1
3668
+33788355744EOF
3669
+Mode: 444
3670
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3671
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/resid_cnt
3672
+Lines: 1
3673
+19EOF
3674
+Mode: 444
3675
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3676
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/write_byte_cnt
3677
+Lines: 1
3678
+1496246784000EOF
3679
+Mode: 444
3680
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3681
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/write_cnt
3682
+Lines: 1
3683
+53772916EOF
3684
+Mode: 444
3685
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3686
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/write_ns
3687
+Lines: 1
3688
+5233597394395EOF
3689
+Mode: 444
3690
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3691
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0
3692
+Mode: 755
3693
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3694
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats
3695
+Mode: 755
3696
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3697
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/in_flight
3698
+Lines: 1
3699
+1EOF
3700
+Mode: 444
3701
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3702
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/io_ns
3703
+Lines: 1
3704
+9247011087720EOF
3705
+Mode: 444
3706
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3707
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/other_cnt
3708
+Lines: 1
3709
+1409EOF
3710
+Mode: 444
3711
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3712
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/read_byte_cnt
3713
+Lines: 1
3714
+979383912EOF
3715
+Mode: 444
3716
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3717
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/read_cnt
3718
+Lines: 1
3719
+3741EOF
3720
+Mode: 444
3721
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3722
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/read_ns
3723
+Lines: 1
3724
+33788355744EOF
3725
+Mode: 444
3726
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3727
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/resid_cnt
3728
+Lines: 1
3729
+19EOF
3730
+Mode: 444
3731
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3732
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/write_byte_cnt
3733
+Lines: 1
3734
+1496246784000EOF
3735
+Mode: 444
3736
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3737
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/write_cnt
3738
+Lines: 1
3739
+53772916EOF
3740
+Mode: 444
3741
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3742
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/write_ns
3743
+Lines: 1
3744
+5233597394395EOF
3745
+Mode: 444
3746
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3747
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a
3748
+Mode: 755
3749
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3750
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats
3751
+Mode: 755
3752
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3753
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/in_flight
3754
+Lines: 1
3755
+1EOF
3756
+Mode: 444
3757
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3758
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/io_ns
3759
+Lines: 1
3760
+9247011087720EOF
3761
+Mode: 444
3762
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3763
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/other_cnt
3764
+Lines: 1
3765
+1409EOF
3766
+Mode: 444
3767
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3768
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/read_byte_cnt
3769
+Lines: 1
3770
+979383912EOF
3771
+Mode: 444
3772
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3773
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/read_cnt
3774
+Lines: 1
3775
+3741EOF
3776
+Mode: 444
3777
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3778
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/read_ns
3779
+Lines: 1
3780
+33788355744EOF
3781
+Mode: 444
3782
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3783
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/resid_cnt
3784
+Lines: 1
3785
+19EOF
3786
+Mode: 444
3787
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3788
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/write_byte_cnt
3789
+Lines: 1
3790
+1496246784000EOF
3791
+Mode: 444
3792
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3793
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/write_cnt
3794
+Lines: 1
3795
+53772916EOF
3796
+Mode: 444
3797
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3798
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/write_ns
3799
+Lines: 1
3800
+5233597394395EOF
3801
+Mode: 444
3802
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3803
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l
3804
+Mode: 755
3805
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3806
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats
3807
+Mode: 755
3808
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3809
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/in_flight
3810
+Lines: 1
3811
+1EOF
3812
+Mode: 444
3813
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3814
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/io_ns
3815
+Lines: 1
3816
+9247011087720EOF
3817
+Mode: 444
3818
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3819
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/other_cnt
3820
+Lines: 1
3821
+1409EOF
3822
+Mode: 444
3823
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3824
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/read_byte_cnt
3825
+Lines: 1
3826
+979383912EOF
3827
+Mode: 444
3828
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3829
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/read_cnt
3830
+Lines: 1
3831
+3741EOF
3832
+Mode: 444
3833
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3834
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/read_ns
3835
+Lines: 1
3836
+33788355744EOF
3837
+Mode: 444
3838
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3839
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/resid_cnt
3840
+Lines: 1
3841
+19EOF
3842
+Mode: 444
3843
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3844
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/write_byte_cnt
3845
+Lines: 1
3846
+1496246784000EOF
3847
+Mode: 444
3848
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3849
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/write_cnt
3850
+Lines: 1
3851
+53772916EOF
3852
+Mode: 444
3853
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3854
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/write_ns
3855
+Lines: 1
3856
+5233597394395EOF
3857
+Mode: 444
3858
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3859
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m
3860
+Mode: 755
3861
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3862
+Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats
3863
+Mode: 755
3864
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3865
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/in_flight
3866
+Lines: 1
3867
+1EOF
3868
+Mode: 444
3869
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3870
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/io_ns
3871
+Lines: 1
3872
+9247011087720EOF
3873
+Mode: 444
3874
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3875
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/other_cnt
3876
+Lines: 1
3877
+1409EOF
3878
+Mode: 444
3879
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3880
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/read_byte_cnt
3881
+Lines: 1
3882
+979383912EOF
3883
+Mode: 444
3884
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3885
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/read_cnt
3886
+Lines: 1
3887
+3741EOF
3888
+Mode: 444
3889
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3890
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/read_ns
3891
+Lines: 1
3892
+33788355744EOF
3893
+Mode: 444
3894
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3895
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/resid_cnt
3896
+Lines: 1
3897
+19EOF
3898
+Mode: 444
3899
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3900
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/write_byte_cnt
3901
+Lines: 1
3902
+1496246784000EOF
3903
+Mode: 444
3904
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3905
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/write_cnt
3906
+Lines: 1
3907
+53772916EOF
3908
+Mode: 444
3909
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3910
+Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/write_ns
3911
+Lines: 1
3912
+5233597394395EOF
3913
+Mode: 444
3914
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3446 3915
 Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0
3447 3916
 Mode: 755
3448 3917
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
... ...
@@ -4093,6 +6345,35 @@ Mode: 644
4093 4093
 Directory: fixtures/sys/devices/system/cpu/cpufreq/policy1
4094 4094
 Mode: 755
4095 4095
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4096
+Directory: fixtures/sys/devices/system/node
4097
+Mode: 775
4098
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4099
+Directory: fixtures/sys/devices/system/node/node1
4100
+Mode: 755
4101
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4102
+Path: fixtures/sys/devices/system/node/node1/vmstat
4103
+Lines: 6
4104
+nr_free_pages 1
4105
+nr_zone_inactive_anon 2
4106
+nr_zone_active_anon 3
4107
+nr_zone_inactive_file 4
4108
+nr_zone_active_file 5
4109
+nr_zone_unevictable 6
4110
+Mode: 644
4111
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4112
+Directory: fixtures/sys/devices/system/node/node2
4113
+Mode: 755
4114
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4115
+Path: fixtures/sys/devices/system/node/node2/vmstat
4116
+Lines: 6
4117
+nr_free_pages 7
4118
+nr_zone_inactive_anon 8
4119
+nr_zone_active_anon 9
4120
+nr_zone_inactive_file 10
4121
+nr_zone_active_file 11
4122
+nr_zone_unevictable 12
4123
+Mode: 644
4124
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4096 4125
 Directory: fixtures/sys/fs
4097 4126
 Mode: 755
4098 4127
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
... ...
@@ -4287,6 +6568,17 @@ Lines: 1
4287 4287
 0
4288 4288
 Mode: 644
4289 4289
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4290
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/writeback_rate_debug
4291
+Lines: 7
4292
+rate:           1.1M/sec
4293
+dirty:          20.4G
4294
+target:         20.4G
4295
+proportional:   427.5k
4296
+integral:       790.0k
4297
+change:         321.5k/sec
4298
+next io:        17ms
4299
+Mode: 644
4300
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4290 4301
 Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/btree_cache_size
4291 4302
 Lines: 1
4292 4303
 0
4293 4304
new file mode 100644
... ...
@@ -0,0 +1,422 @@
0
+// Copyright 2019 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+package procfs
14
+
15
+import (
16
+	"bufio"
17
+	"bytes"
18
+	"fmt"
19
+	"io"
20
+	"strconv"
21
+	"strings"
22
+
23
+	"github.com/prometheus/procfs/internal/util"
24
+)
25
+
26
+// Fscacheinfo represents fscache statistics.
27
+type Fscacheinfo struct {
28
+	// Number of index cookies allocated
29
+	IndexCookiesAllocated uint64
30
+	// data storage cookies allocated
31
+	DataStorageCookiesAllocated uint64
32
+	// Number of special cookies allocated
33
+	SpecialCookiesAllocated uint64
34
+	// Number of objects allocated
35
+	ObjectsAllocated uint64
36
+	// Number of object allocation failures
37
+	ObjectAllocationsFailure uint64
38
+	// Number of objects that reached the available state
39
+	ObjectsAvailable uint64
40
+	// Number of objects that reached the dead state
41
+	ObjectsDead uint64
42
+	// Number of objects that didn't have a coherency check
43
+	ObjectsWithoutCoherencyCheck uint64
44
+	// Number of objects that passed a coherency check
45
+	ObjectsWithCoherencyCheck uint64
46
+	// Number of objects that needed a coherency data update
47
+	ObjectsNeedCoherencyCheckUpdate uint64
48
+	// Number of objects that were declared obsolete
49
+	ObjectsDeclaredObsolete uint64
50
+	// Number of pages marked as being cached
51
+	PagesMarkedAsBeingCached uint64
52
+	// Number of uncache page requests seen
53
+	UncachePagesRequestSeen uint64
54
+	// Number of acquire cookie requests seen
55
+	AcquireCookiesRequestSeen uint64
56
+	// Number of acq reqs given a NULL parent
57
+	AcquireRequestsWithNullParent uint64
58
+	// Number of acq reqs rejected due to no cache available
59
+	AcquireRequestsRejectedNoCacheAvailable uint64
60
+	// Number of acq reqs succeeded
61
+	AcquireRequestsSucceeded uint64
62
+	// Number of acq reqs rejected due to error
63
+	AcquireRequestsRejectedDueToError uint64
64
+	// Number of acq reqs failed on ENOMEM
65
+	AcquireRequestsFailedDueToEnomem uint64
66
+	// Number of lookup calls made on cache backends
67
+	LookupsNumber uint64
68
+	// Number of negative lookups made
69
+	LookupsNegative uint64
70
+	// Number of positive lookups made
71
+	LookupsPositive uint64
72
+	// Number of objects created by lookup
73
+	ObjectsCreatedByLookup uint64
74
+	// Number of lookups timed out and requeued
75
+	LookupsTimedOutAndRequed uint64
76
+	InvalidationsNumber      uint64
77
+	InvalidationsRunning     uint64
78
+	// Number of update cookie requests seen
79
+	UpdateCookieRequestSeen uint64
80
+	// Number of upd reqs given a NULL parent
81
+	UpdateRequestsWithNullParent uint64
82
+	// Number of upd reqs granted CPU time
83
+	UpdateRequestsRunning uint64
84
+	// Number of relinquish cookie requests seen
85
+	RelinquishCookiesRequestSeen uint64
86
+	// Number of rlq reqs given a NULL parent
87
+	RelinquishCookiesWithNullParent uint64
88
+	// Number of rlq reqs waited on completion of creation
89
+	RelinquishRequestsWaitingCompleteCreation uint64
90
+	// Relinqs rtr
91
+	RelinquishRetries uint64
92
+	// Number of attribute changed requests seen
93
+	AttributeChangedRequestsSeen uint64
94
+	// Number of attr changed requests queued
95
+	AttributeChangedRequestsQueued uint64
96
+	// Number of attr changed rejected -ENOBUFS
97
+	AttributeChangedRejectDueToEnobufs uint64
98
+	// Number of attr changed failed -ENOMEM
99
+	AttributeChangedFailedDueToEnomem uint64
100
+	// Number of attr changed ops given CPU time
101
+	AttributeChangedOps uint64
102
+	// Number of allocation requests seen
103
+	AllocationRequestsSeen uint64
104
+	// Number of successful alloc reqs
105
+	AllocationOkRequests uint64
106
+	// Number of alloc reqs that waited on lookup completion
107
+	AllocationWaitingOnLookup uint64
108
+	// Number of alloc reqs rejected -ENOBUFS
109
+	AllocationsRejectedDueToEnobufs uint64
110
+	// Number of alloc reqs aborted -ERESTARTSYS
111
+	AllocationsAbortedDueToErestartsys uint64
112
+	// Number of alloc reqs submitted
113
+	AllocationOperationsSubmitted uint64
114
+	// Number of alloc reqs waited for CPU time
115
+	AllocationsWaitedForCPU uint64
116
+	// Number of alloc reqs aborted due to object death
117
+	AllocationsAbortedDueToObjectDeath uint64
118
+	// Number of retrieval (read) requests seen
119
+	RetrievalsReadRequests uint64
120
+	// Number of successful retr reqs
121
+	RetrievalsOk uint64
122
+	// Number of retr reqs that waited on lookup completion
123
+	RetrievalsWaitingLookupCompletion uint64
124
+	// Number of retr reqs returned -ENODATA
125
+	RetrievalsReturnedEnodata uint64
126
+	// Number of retr reqs rejected -ENOBUFS
127
+	RetrievalsRejectedDueToEnobufs uint64
128
+	// Number of retr reqs aborted -ERESTARTSYS
129
+	RetrievalsAbortedDueToErestartsys uint64
130
+	// Number of retr reqs failed -ENOMEM
131
+	RetrievalsFailedDueToEnomem uint64
132
+	// Number of retr reqs submitted
133
+	RetrievalsRequests uint64
134
+	// Number of retr reqs waited for CPU time
135
+	RetrievalsWaitingCPU uint64
136
+	// Number of retr reqs aborted due to object death
137
+	RetrievalsAbortedDueToObjectDeath uint64
138
+	// Number of storage (write) requests seen
139
+	StoreWriteRequests uint64
140
+	// Number of successful store reqs
141
+	StoreSuccessfulRequests uint64
142
+	// Number of store reqs on a page already pending storage
143
+	StoreRequestsOnPendingStorage uint64
144
+	// Number of store reqs rejected -ENOBUFS
145
+	StoreRequestsRejectedDueToEnobufs uint64
146
+	// Number of store reqs failed -ENOMEM
147
+	StoreRequestsFailedDueToEnomem uint64
148
+	// Number of store reqs submitted
149
+	StoreRequestsSubmitted uint64
150
+	// Number of store reqs granted CPU time
151
+	StoreRequestsRunning uint64
152
+	// Number of pages given store req processing time
153
+	StorePagesWithRequestsProcessing uint64
154
+	// Number of store reqs deleted from tracking tree
155
+	StoreRequestsDeleted uint64
156
+	// Number of store reqs over store limit
157
+	StoreRequestsOverStoreLimit uint64
158
+	// Number of release reqs against pages with no pending store
159
+	ReleaseRequestsAgainstPagesWithNoPendingStorage uint64
160
+	// Number of release reqs against pages stored by time lock granted
161
+	ReleaseRequestsAgainstPagesStoredByTimeLockGranted uint64
162
+	// Number of release reqs ignored due to in-progress store
163
+	ReleaseRequestsIgnoredDueToInProgressStore uint64
164
+	// Number of page stores cancelled due to release req
165
+	PageStoresCancelledByReleaseRequests uint64
166
+	VmscanWaiting                        uint64
167
+	// Number of times async ops added to pending queues
168
+	OpsPending uint64
169
+	// Number of times async ops given CPU time
170
+	OpsRunning uint64
171
+	// Number of times async ops queued for processing
172
+	OpsEnqueued uint64
173
+	// Number of async ops cancelled
174
+	OpsCancelled uint64
175
+	// Number of async ops rejected due to object lookup/create failure
176
+	OpsRejected uint64
177
+	// Number of async ops initialised
178
+	OpsInitialised uint64
179
+	// Number of async ops queued for deferred release
180
+	OpsDeferred uint64
181
+	// Number of async ops released (should equal ini=N when idle)
182
+	OpsReleased uint64
183
+	// Number of deferred-release async ops garbage collected
184
+	OpsGarbageCollected uint64
185
+	// Number of in-progress alloc_object() cache ops
186
+	CacheopAllocationsinProgress uint64
187
+	// Number of in-progress lookup_object() cache ops
188
+	CacheopLookupObjectInProgress uint64
189
+	// Number of in-progress lookup_complete() cache ops
190
+	CacheopLookupCompleteInPorgress uint64
191
+	// Number of in-progress grab_object() cache ops
192
+	CacheopGrabObjectInProgress uint64
193
+	CacheopInvalidations        uint64
194
+	// Number of in-progress update_object() cache ops
195
+	CacheopUpdateObjectInProgress uint64
196
+	// Number of in-progress drop_object() cache ops
197
+	CacheopDropObjectInProgress uint64
198
+	// Number of in-progress put_object() cache ops
199
+	CacheopPutObjectInProgress uint64
200
+	// Number of in-progress attr_changed() cache ops
201
+	CacheopAttributeChangeInProgress uint64
202
+	// Number of in-progress sync_cache() cache ops
203
+	CacheopSyncCacheInProgress uint64
204
+	// Number of in-progress read_or_alloc_page() cache ops
205
+	CacheopReadOrAllocPageInProgress uint64
206
+	// Number of in-progress read_or_alloc_pages() cache ops
207
+	CacheopReadOrAllocPagesInProgress uint64
208
+	// Number of in-progress allocate_page() cache ops
209
+	CacheopAllocatePageInProgress uint64
210
+	// Number of in-progress allocate_pages() cache ops
211
+	CacheopAllocatePagesInProgress uint64
212
+	// Number of in-progress write_page() cache ops
213
+	CacheopWritePagesInProgress uint64
214
+	// Number of in-progress uncache_page() cache ops
215
+	CacheopUncachePagesInProgress uint64
216
+	// Number of in-progress dissociate_pages() cache ops
217
+	CacheopDissociatePagesInProgress uint64
218
+	// Number of object lookups/creations rejected due to lack of space
219
+	CacheevLookupsAndCreationsRejectedLackSpace uint64
220
+	// Number of stale objects deleted
221
+	CacheevStaleObjectsDeleted uint64
222
+	// Number of objects retired when relinquished
223
+	CacheevRetiredWhenReliquished uint64
224
+	// Number of objects culled
225
+	CacheevObjectsCulled uint64
226
+}
227
+
228
+// Fscacheinfo returns information about current fscache statistics.
229
+// See https://www.kernel.org/doc/Documentation/filesystems/caching/fscache.txt
230
+func (fs FS) Fscacheinfo() (Fscacheinfo, error) {
231
+	b, err := util.ReadFileNoStat(fs.proc.Path("fs/fscache/stats"))
232
+	if err != nil {
233
+		return Fscacheinfo{}, err
234
+	}
235
+
236
+	m, err := parseFscacheinfo(bytes.NewReader(b))
237
+	if err != nil {
238
+		return Fscacheinfo{}, fmt.Errorf("failed to parse Fscacheinfo: %w", err)
239
+	}
240
+
241
+	return *m, nil
242
+}
243
+
244
+func setFSCacheFields(fields []string, setFields ...*uint64) error {
245
+	var err error
246
+	if len(fields) < len(setFields) {
247
+		return fmt.Errorf("Insufficient number of fields, expected %v, got %v", len(setFields), len(fields))
248
+	}
249
+
250
+	for i := range setFields {
251
+		*setFields[i], err = strconv.ParseUint(strings.Split(fields[i], "=")[1], 0, 64)
252
+		if err != nil {
253
+			return err
254
+		}
255
+	}
256
+	return nil
257
+}
258
+
259
+func parseFscacheinfo(r io.Reader) (*Fscacheinfo, error) {
260
+	var m Fscacheinfo
261
+	s := bufio.NewScanner(r)
262
+	for s.Scan() {
263
+		fields := strings.Fields(s.Text())
264
+		if len(fields) < 2 {
265
+			return nil, fmt.Errorf("malformed Fscacheinfo line: %q", s.Text())
266
+		}
267
+
268
+		switch fields[0] {
269
+		case "Cookies:":
270
+			err := setFSCacheFields(fields[1:], &m.IndexCookiesAllocated, &m.DataStorageCookiesAllocated,
271
+				&m.SpecialCookiesAllocated)
272
+			if err != nil {
273
+				return &m, err
274
+			}
275
+		case "Objects:":
276
+			err := setFSCacheFields(fields[1:], &m.ObjectsAllocated, &m.ObjectAllocationsFailure,
277
+				&m.ObjectsAvailable, &m.ObjectsDead)
278
+			if err != nil {
279
+				return &m, err
280
+			}
281
+		case "ChkAux":
282
+			err := setFSCacheFields(fields[2:], &m.ObjectsWithoutCoherencyCheck, &m.ObjectsWithCoherencyCheck,
283
+				&m.ObjectsNeedCoherencyCheckUpdate, &m.ObjectsDeclaredObsolete)
284
+			if err != nil {
285
+				return &m, err
286
+			}
287
+		case "Pages":
288
+			err := setFSCacheFields(fields[2:], &m.PagesMarkedAsBeingCached, &m.UncachePagesRequestSeen)
289
+			if err != nil {
290
+				return &m, err
291
+			}
292
+		case "Acquire:":
293
+			err := setFSCacheFields(fields[1:], &m.AcquireCookiesRequestSeen, &m.AcquireRequestsWithNullParent,
294
+				&m.AcquireRequestsRejectedNoCacheAvailable, &m.AcquireRequestsSucceeded, &m.AcquireRequestsRejectedDueToError,
295
+				&m.AcquireRequestsFailedDueToEnomem)
296
+			if err != nil {
297
+				return &m, err
298
+			}
299
+		case "Lookups:":
300
+			err := setFSCacheFields(fields[1:], &m.LookupsNumber, &m.LookupsNegative, &m.LookupsPositive,
301
+				&m.ObjectsCreatedByLookup, &m.LookupsTimedOutAndRequed)
302
+			if err != nil {
303
+				return &m, err
304
+			}
305
+		case "Invals":
306
+			err := setFSCacheFields(fields[2:], &m.InvalidationsNumber, &m.InvalidationsRunning)
307
+			if err != nil {
308
+				return &m, err
309
+			}
310
+		case "Updates:":
311
+			err := setFSCacheFields(fields[1:], &m.UpdateCookieRequestSeen, &m.UpdateRequestsWithNullParent,
312
+				&m.UpdateRequestsRunning)
313
+			if err != nil {
314
+				return &m, err
315
+			}
316
+		case "Relinqs:":
317
+			err := setFSCacheFields(fields[1:], &m.RelinquishCookiesRequestSeen, &m.RelinquishCookiesWithNullParent,
318
+				&m.RelinquishRequestsWaitingCompleteCreation, &m.RelinquishRetries)
319
+			if err != nil {
320
+				return &m, err
321
+			}
322
+		case "AttrChg:":
323
+			err := setFSCacheFields(fields[1:], &m.AttributeChangedRequestsSeen, &m.AttributeChangedRequestsQueued,
324
+				&m.AttributeChangedRejectDueToEnobufs, &m.AttributeChangedFailedDueToEnomem, &m.AttributeChangedOps)
325
+			if err != nil {
326
+				return &m, err
327
+			}
328
+		case "Allocs":
329
+			if strings.Split(fields[2], "=")[0] == "n" {
330
+				err := setFSCacheFields(fields[2:], &m.AllocationRequestsSeen, &m.AllocationOkRequests,
331
+					&m.AllocationWaitingOnLookup, &m.AllocationsRejectedDueToEnobufs, &m.AllocationsAbortedDueToErestartsys)
332
+				if err != nil {
333
+					return &m, err
334
+				}
335
+			} else {
336
+				err := setFSCacheFields(fields[2:], &m.AllocationOperationsSubmitted, &m.AllocationsWaitedForCPU,
337
+					&m.AllocationsAbortedDueToObjectDeath)
338
+				if err != nil {
339
+					return &m, err
340
+				}
341
+			}
342
+		case "Retrvls:":
343
+			if strings.Split(fields[1], "=")[0] == "n" {
344
+				err := setFSCacheFields(fields[1:], &m.RetrievalsReadRequests, &m.RetrievalsOk, &m.RetrievalsWaitingLookupCompletion,
345
+					&m.RetrievalsReturnedEnodata, &m.RetrievalsRejectedDueToEnobufs, &m.RetrievalsAbortedDueToErestartsys,
346
+					&m.RetrievalsFailedDueToEnomem)
347
+				if err != nil {
348
+					return &m, err
349
+				}
350
+			} else {
351
+				err := setFSCacheFields(fields[1:], &m.RetrievalsRequests, &m.RetrievalsWaitingCPU, &m.RetrievalsAbortedDueToObjectDeath)
352
+				if err != nil {
353
+					return &m, err
354
+				}
355
+			}
356
+		case "Stores":
357
+			if strings.Split(fields[2], "=")[0] == "n" {
358
+				err := setFSCacheFields(fields[2:], &m.StoreWriteRequests, &m.StoreSuccessfulRequests,
359
+					&m.StoreRequestsOnPendingStorage, &m.StoreRequestsRejectedDueToEnobufs, &m.StoreRequestsFailedDueToEnomem)
360
+				if err != nil {
361
+					return &m, err
362
+				}
363
+			} else {
364
+				err := setFSCacheFields(fields[2:], &m.StoreRequestsSubmitted, &m.StoreRequestsRunning,
365
+					&m.StorePagesWithRequestsProcessing, &m.StoreRequestsDeleted, &m.StoreRequestsOverStoreLimit)
366
+				if err != nil {
367
+					return &m, err
368
+				}
369
+			}
370
+		case "VmScan":
371
+			err := setFSCacheFields(fields[2:], &m.ReleaseRequestsAgainstPagesWithNoPendingStorage,
372
+				&m.ReleaseRequestsAgainstPagesStoredByTimeLockGranted, &m.ReleaseRequestsIgnoredDueToInProgressStore,
373
+				&m.PageStoresCancelledByReleaseRequests, &m.VmscanWaiting)
374
+			if err != nil {
375
+				return &m, err
376
+			}
377
+		case "Ops":
378
+			if strings.Split(fields[2], "=")[0] == "pend" {
379
+				err := setFSCacheFields(fields[2:], &m.OpsPending, &m.OpsRunning, &m.OpsEnqueued, &m.OpsCancelled, &m.OpsRejected)
380
+				if err != nil {
381
+					return &m, err
382
+				}
383
+			} else {
384
+				err := setFSCacheFields(fields[2:], &m.OpsInitialised, &m.OpsDeferred, &m.OpsReleased, &m.OpsGarbageCollected)
385
+				if err != nil {
386
+					return &m, err
387
+				}
388
+			}
389
+		case "CacheOp:":
390
+			if strings.Split(fields[1], "=")[0] == "alo" {
391
+				err := setFSCacheFields(fields[1:], &m.CacheopAllocationsinProgress, &m.CacheopLookupObjectInProgress,
392
+					&m.CacheopLookupCompleteInPorgress, &m.CacheopGrabObjectInProgress)
393
+				if err != nil {
394
+					return &m, err
395
+				}
396
+			} else if strings.Split(fields[1], "=")[0] == "inv" {
397
+				err := setFSCacheFields(fields[1:], &m.CacheopInvalidations, &m.CacheopUpdateObjectInProgress,
398
+					&m.CacheopDropObjectInProgress, &m.CacheopPutObjectInProgress, &m.CacheopAttributeChangeInProgress,
399
+					&m.CacheopSyncCacheInProgress)
400
+				if err != nil {
401
+					return &m, err
402
+				}
403
+			} else {
404
+				err := setFSCacheFields(fields[1:], &m.CacheopReadOrAllocPageInProgress, &m.CacheopReadOrAllocPagesInProgress,
405
+					&m.CacheopAllocatePageInProgress, &m.CacheopAllocatePagesInProgress, &m.CacheopWritePagesInProgress,
406
+					&m.CacheopUncachePagesInProgress, &m.CacheopDissociatePagesInProgress)
407
+				if err != nil {
408
+					return &m, err
409
+				}
410
+			}
411
+		case "CacheEv:":
412
+			err := setFSCacheFields(fields[1:], &m.CacheevLookupsAndCreationsRejectedLackSpace, &m.CacheevStaleObjectsDeleted,
413
+				&m.CacheevRetiredWhenReliquished, &m.CacheevObjectsCulled)
414
+			if err != nil {
415
+				return &m, err
416
+			}
417
+		}
418
+	}
419
+
420
+	return &m, nil
421
+}
... ...
@@ -39,10 +39,10 @@ type FS string
39 39
 func NewFS(mountPoint string) (FS, error) {
40 40
 	info, err := os.Stat(mountPoint)
41 41
 	if err != nil {
42
-		return "", fmt.Errorf("could not read %s: %s", mountPoint, err)
42
+		return "", fmt.Errorf("could not read %q: %w", mountPoint, err)
43 43
 	}
44 44
 	if !info.IsDir() {
45
-		return "", fmt.Errorf("mount point %s is not a directory", mountPoint)
45
+		return "", fmt.Errorf("mount point %q is not a directory", mountPoint)
46 46
 	}
47 47
 
48 48
 	return FS(mountPoint), nil
... ...
@@ -73,6 +73,15 @@ func ReadUintFromFile(path string) (uint64, error) {
73 73
 	return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
74 74
 }
75 75
 
76
+// ReadIntFromFile reads a file and attempts to parse a int64 from it.
77
+func ReadIntFromFile(path string) (int64, error) {
78
+	data, err := ioutil.ReadFile(path)
79
+	if err != nil {
80
+		return 0, err
81
+	}
82
+	return strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64)
83
+}
84
+
76 85
 // ParseBool parses a string into a boolean pointer.
77 86
 func ParseBool(b string) *bool {
78 87
 	var truth bool
79 88
new file mode 100644
... ...
@@ -0,0 +1,62 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+// +build !windows
14
+
15
+package procfs
16
+
17
+import (
18
+	"os"
19
+
20
+	"github.com/prometheus/procfs/internal/util"
21
+)
22
+
23
+// KernelRandom contains information about to the kernel's random number generator.
24
+type KernelRandom struct {
25
+	// EntropyAvaliable gives the available entropy, in bits.
26
+	EntropyAvaliable *uint64
27
+	// PoolSize gives the size of the entropy pool, in bits.
28
+	PoolSize *uint64
29
+	// URandomMinReseedSeconds is the number of seconds after which the DRNG will be reseeded.
30
+	URandomMinReseedSeconds *uint64
31
+	// WriteWakeupThreshold the number of bits of entropy below which we wake up processes
32
+	// that do a select(2) or poll(2) for write access to /dev/random.
33
+	WriteWakeupThreshold *uint64
34
+	// ReadWakeupThreshold is the number of bits of entropy required for waking up processes that sleep
35
+	// waiting for entropy from /dev/random.
36
+	ReadWakeupThreshold *uint64
37
+}
38
+
39
+// KernelRandom returns values from /proc/sys/kernel/random.
40
+func (fs FS) KernelRandom() (KernelRandom, error) {
41
+	random := KernelRandom{}
42
+
43
+	for file, p := range map[string]**uint64{
44
+		"entropy_avail":           &random.EntropyAvaliable,
45
+		"poolsize":                &random.PoolSize,
46
+		"urandom_min_reseed_secs": &random.URandomMinReseedSeconds,
47
+		"write_wakeup_threshold":  &random.WriteWakeupThreshold,
48
+		"read_wakeup_threshold":   &random.ReadWakeupThreshold,
49
+	} {
50
+		val, err := util.ReadUintFromFile(fs.proc.Path("sys", "kernel", "random", file))
51
+		if os.IsNotExist(err) {
52
+			continue
53
+		}
54
+		if err != nil {
55
+			return random, err
56
+		}
57
+		*p = &val
58
+	}
59
+
60
+	return random, nil
61
+}
... ...
@@ -44,14 +44,14 @@ func parseLoad(loadavgBytes []byte) (*LoadAvg, error) {
44 44
 	loads := make([]float64, 3)
45 45
 	parts := strings.Fields(string(loadavgBytes))
46 46
 	if len(parts) < 3 {
47
-		return nil, fmt.Errorf("malformed loadavg line: too few fields in loadavg string: %s", string(loadavgBytes))
47
+		return nil, fmt.Errorf("malformed loadavg line: too few fields in loadavg string: %q", string(loadavgBytes))
48 48
 	}
49 49
 
50 50
 	var err error
51 51
 	for i, load := range parts[0:3] {
52 52
 		loads[i], err = strconv.ParseFloat(load, 64)
53 53
 		if err != nil {
54
-			return nil, fmt.Errorf("could not parse load '%s': %s", load, err)
54
+			return nil, fmt.Errorf("could not parse load %q: %w", load, err)
55 55
 		}
56 56
 	}
57 57
 	return &LoadAvg{
... ...
@@ -22,8 +22,12 @@ import (
22 22
 )
23 23
 
24 24
 var (
25
-	statusLineRE   = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[[U_]+\]`)
26
-	recoveryLineRE = regexp.MustCompile(`\((\d+)/\d+\)`)
25
+	statusLineRE         = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[([U_]+)\]`)
26
+	recoveryLineBlocksRE = regexp.MustCompile(`\((\d+)/\d+\)`)
27
+	recoveryLinePctRE    = regexp.MustCompile(`= (.+)%`)
28
+	recoveryLineFinishRE = regexp.MustCompile(`finish=(.+)min`)
29
+	recoveryLineSpeedRE  = regexp.MustCompile(`speed=(.+)[A-Z]`)
30
+	componentDeviceRE    = regexp.MustCompile(`(.*)\[\d+\]`)
27 31
 )
28 32
 
29 33
 // MDStat holds info parsed from /proc/mdstat.
... ...
@@ -38,12 +42,22 @@ type MDStat struct {
38 38
 	DisksTotal int64
39 39
 	// Number of failed disks.
40 40
 	DisksFailed int64
41
+	// Number of "down" disks. (the _ indicator in the status line)
42
+	DisksDown int64
41 43
 	// Spare disks in the device.
42 44
 	DisksSpare int64
43 45
 	// Number of blocks the device holds.
44 46
 	BlocksTotal int64
45 47
 	// Number of blocks on the device that are in sync.
46 48
 	BlocksSynced int64
49
+	// progress percentage of current sync
50
+	BlocksSyncedPct float64
51
+	// estimated finishing time for current sync (in minutes)
52
+	BlocksSyncedFinishTime float64
53
+	// current sync speed (in Kilobytes/sec)
54
+	BlocksSyncedSpeed float64
55
+	// Name of md component devices
56
+	Devices []string
47 57
 }
48 58
 
49 59
 // MDStat parses an mdstat-file (/proc/mdstat) and returns a slice of
... ...
@@ -52,11 +66,11 @@ type MDStat struct {
52 52
 func (fs FS) MDStat() ([]MDStat, error) {
53 53
 	data, err := ioutil.ReadFile(fs.proc.Path("mdstat"))
54 54
 	if err != nil {
55
-		return nil, fmt.Errorf("error parsing mdstat %s: %s", fs.proc.Path("mdstat"), err)
55
+		return nil, err
56 56
 	}
57 57
 	mdstat, err := parseMDStat(data)
58 58
 	if err != nil {
59
-		return nil, fmt.Errorf("error parsing mdstat %s: %s", fs.proc.Path("mdstat"), err)
59
+		return nil, fmt.Errorf("error parsing mdstat %q: %w", fs.proc.Path("mdstat"), err)
60 60
 	}
61 61
 	return mdstat, nil
62 62
 }
... ...
@@ -82,19 +96,16 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
82 82
 		state := deviceFields[2]  // active or inactive
83 83
 
84 84
 		if len(lines) <= i+3 {
85
-			return nil, fmt.Errorf(
86
-				"error parsing %s: too few lines for md device",
87
-				mdName,
88
-			)
85
+			return nil, fmt.Errorf("error parsing %q: too few lines for md device", mdName)
89 86
 		}
90 87
 
91 88
 		// Failed disks have the suffix (F) & Spare disks have the suffix (S).
92 89
 		fail := int64(strings.Count(line, "(F)"))
93 90
 		spare := int64(strings.Count(line, "(S)"))
94
-		active, total, size, err := evalStatusLine(lines[i], lines[i+1])
91
+		active, total, down, size, err := evalStatusLine(lines[i], lines[i+1])
95 92
 
96 93
 		if err != nil {
97
-			return nil, fmt.Errorf("error parsing md device lines: %s", err)
94
+			return nil, fmt.Errorf("error parsing md device lines: %w", err)
98 95
 		}
99 96
 
100 97
 		syncLineIdx := i + 2
... ...
@@ -105,13 +116,19 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
105 105
 		// If device is syncing at the moment, get the number of currently
106 106
 		// synced bytes, otherwise that number equals the size of the device.
107 107
 		syncedBlocks := size
108
+		speed := float64(0)
109
+		finish := float64(0)
110
+		pct := float64(0)
108 111
 		recovering := strings.Contains(lines[syncLineIdx], "recovery")
109 112
 		resyncing := strings.Contains(lines[syncLineIdx], "resync")
113
+		checking := strings.Contains(lines[syncLineIdx], "check")
110 114
 
111 115
 		// Append recovery and resyncing state info.
112
-		if recovering || resyncing {
116
+		if recovering || resyncing || checking {
113 117
 			if recovering {
114 118
 				state = "recovering"
119
+			} else if checking {
120
+				state = "checking"
115 121
 			} else {
116 122
 				state = "resyncing"
117 123
 			}
... ...
@@ -121,74 +138,125 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
121 121
 				strings.Contains(lines[syncLineIdx], "DELAYED") {
122 122
 				syncedBlocks = 0
123 123
 			} else {
124
-				syncedBlocks, err = evalRecoveryLine(lines[syncLineIdx])
124
+				syncedBlocks, pct, finish, speed, err = evalRecoveryLine(lines[syncLineIdx])
125 125
 				if err != nil {
126
-					return nil, fmt.Errorf("error parsing sync line in md device %s: %s", mdName, err)
126
+					return nil, fmt.Errorf("error parsing sync line in md device %q: %w", mdName, err)
127 127
 				}
128 128
 			}
129 129
 		}
130 130
 
131 131
 		mdStats = append(mdStats, MDStat{
132
-			Name:          mdName,
133
-			ActivityState: state,
134
-			DisksActive:   active,
135
-			DisksFailed:   fail,
136
-			DisksSpare:    spare,
137
-			DisksTotal:    total,
138
-			BlocksTotal:   size,
139
-			BlocksSynced:  syncedBlocks,
132
+			Name:                   mdName,
133
+			ActivityState:          state,
134
+			DisksActive:            active,
135
+			DisksFailed:            fail,
136
+			DisksDown:              down,
137
+			DisksSpare:             spare,
138
+			DisksTotal:             total,
139
+			BlocksTotal:            size,
140
+			BlocksSynced:           syncedBlocks,
141
+			BlocksSyncedPct:        pct,
142
+			BlocksSyncedFinishTime: finish,
143
+			BlocksSyncedSpeed:      speed,
144
+			Devices:                evalComponentDevices(deviceFields),
140 145
 		})
141 146
 	}
142 147
 
143 148
 	return mdStats, nil
144 149
 }
145 150
 
146
-func evalStatusLine(deviceLine, statusLine string) (active, total, size int64, err error) {
151
+func evalStatusLine(deviceLine, statusLine string) (active, total, down, size int64, err error) {
147 152
 
148 153
 	sizeStr := strings.Fields(statusLine)[0]
149 154
 	size, err = strconv.ParseInt(sizeStr, 10, 64)
150 155
 	if err != nil {
151
-		return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
156
+		return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q: %w", statusLine, err)
152 157
 	}
153 158
 
154 159
 	if strings.Contains(deviceLine, "raid0") || strings.Contains(deviceLine, "linear") {
155 160
 		// In the device deviceLine, only disks have a number associated with them in [].
156 161
 		total = int64(strings.Count(deviceLine, "["))
157
-		return total, total, size, nil
162
+		return total, total, 0, size, nil
158 163
 	}
159 164
 
160 165
 	if strings.Contains(deviceLine, "inactive") {
161
-		return 0, 0, size, nil
166
+		return 0, 0, 0, size, nil
162 167
 	}
163 168
 
164 169
 	matches := statusLineRE.FindStringSubmatch(statusLine)
165
-	if len(matches) != 4 {
166
-		return 0, 0, 0, fmt.Errorf("couldn't find all the substring matches: %s", statusLine)
170
+	if len(matches) != 5 {
171
+		return 0, 0, 0, 0, fmt.Errorf("couldn't find all the substring matches: %s", statusLine)
167 172
 	}
168 173
 
169 174
 	total, err = strconv.ParseInt(matches[2], 10, 64)
170 175
 	if err != nil {
171
-		return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
176
+		return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q: %w", statusLine, err)
172 177
 	}
173 178
 
174 179
 	active, err = strconv.ParseInt(matches[3], 10, 64)
175 180
 	if err != nil {
176
-		return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
181
+		return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q: %w", statusLine, err)
177 182
 	}
183
+	down = int64(strings.Count(matches[4], "_"))
178 184
 
179
-	return active, total, size, nil
185
+	return active, total, down, size, nil
180 186
 }
181 187
 
182
-func evalRecoveryLine(recoveryLine string) (syncedBlocks int64, err error) {
183
-	matches := recoveryLineRE.FindStringSubmatch(recoveryLine)
188
+func evalRecoveryLine(recoveryLine string) (syncedBlocks int64, pct float64, finish float64, speed float64, err error) {
189
+	matches := recoveryLineBlocksRE.FindStringSubmatch(recoveryLine)
184 190
 	if len(matches) != 2 {
185
-		return 0, fmt.Errorf("unexpected recoveryLine: %s", recoveryLine)
191
+		return 0, 0, 0, 0, fmt.Errorf("unexpected recoveryLine: %s", recoveryLine)
186 192
 	}
187 193
 
188 194
 	syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64)
189 195
 	if err != nil {
190
-		return 0, fmt.Errorf("%s in recoveryLine: %s", err, recoveryLine)
196
+		return 0, 0, 0, 0, fmt.Errorf("error parsing int from recoveryLine %q: %w", recoveryLine, err)
191 197
 	}
192 198
 
193
-	return syncedBlocks, nil
199
+	// Get percentage complete
200
+	matches = recoveryLinePctRE.FindStringSubmatch(recoveryLine)
201
+	if len(matches) != 2 {
202
+		return syncedBlocks, 0, 0, 0, fmt.Errorf("unexpected recoveryLine matching percentage: %s", recoveryLine)
203
+	}
204
+	pct, err = strconv.ParseFloat(strings.TrimSpace(matches[1]), 64)
205
+	if err != nil {
206
+		return syncedBlocks, 0, 0, 0, fmt.Errorf("error parsing float from recoveryLine %q: %w", recoveryLine, err)
207
+	}
208
+
209
+	// Get time expected left to complete
210
+	matches = recoveryLineFinishRE.FindStringSubmatch(recoveryLine)
211
+	if len(matches) != 2 {
212
+		return syncedBlocks, pct, 0, 0, fmt.Errorf("unexpected recoveryLine matching est. finish time: %s", recoveryLine)
213
+	}
214
+	finish, err = strconv.ParseFloat(matches[1], 64)
215
+	if err != nil {
216
+		return syncedBlocks, pct, 0, 0, fmt.Errorf("error parsing float from recoveryLine %q: %w", recoveryLine, err)
217
+	}
218
+
219
+	// Get recovery speed
220
+	matches = recoveryLineSpeedRE.FindStringSubmatch(recoveryLine)
221
+	if len(matches) != 2 {
222
+		return syncedBlocks, pct, finish, 0, fmt.Errorf("unexpected recoveryLine matching speed: %s", recoveryLine)
223
+	}
224
+	speed, err = strconv.ParseFloat(matches[1], 64)
225
+	if err != nil {
226
+		return syncedBlocks, pct, finish, 0, fmt.Errorf("error parsing float from recoveryLine %q: %w", recoveryLine, err)
227
+	}
228
+
229
+	return syncedBlocks, pct, finish, speed, nil
230
+}
231
+
232
+func evalComponentDevices(deviceFields []string) []string {
233
+	mdComponentDevices := make([]string, 0)
234
+	if len(deviceFields) > 3 {
235
+		for _, field := range deviceFields[4:] {
236
+			match := componentDeviceRE.FindStringSubmatch(field)
237
+			if match == nil {
238
+				continue
239
+			}
240
+			mdComponentDevices = append(mdComponentDevices, match[1])
241
+		}
242
+	}
243
+
244
+	return mdComponentDevices
194 245
 }
... ...
@@ -28,9 +28,9 @@ import (
28 28
 type Meminfo struct {
29 29
 	// Total usable ram (i.e. physical ram minus a few reserved
30 30
 	// bits and the kernel binary code)
31
-	MemTotal uint64
31
+	MemTotal *uint64
32 32
 	// The sum of LowFree+HighFree
33
-	MemFree uint64
33
+	MemFree *uint64
34 34
 	// An estimate of how much memory is available for starting
35 35
 	// new applications, without swapping. Calculated from
36 36
 	// MemFree, SReclaimable, the size of the file LRU lists, and
... ...
@@ -39,59 +39,59 @@ type Meminfo struct {
39 39
 	// well, and that not all reclaimable slab will be
40 40
 	// reclaimable, due to items being in use. The impact of those
41 41
 	// factors will vary from system to system.
42
-	MemAvailable uint64
42
+	MemAvailable *uint64
43 43
 	// Relatively temporary storage for raw disk blocks shouldn't
44 44
 	// get tremendously large (20MB or so)
45
-	Buffers uint64
46
-	Cached  uint64
45
+	Buffers *uint64
46
+	Cached  *uint64
47 47
 	// Memory that once was swapped out, is swapped back in but
48 48
 	// still also is in the swapfile (if memory is needed it
49 49
 	// doesn't need to be swapped out AGAIN because it is already
50 50
 	// in the swapfile. This saves I/O)
51
-	SwapCached uint64
51
+	SwapCached *uint64
52 52
 	// Memory that has been used more recently and usually not
53 53
 	// reclaimed unless absolutely necessary.
54
-	Active uint64
54
+	Active *uint64
55 55
 	// Memory which has been less recently used.  It is more
56 56
 	// eligible to be reclaimed for other purposes
57
-	Inactive     uint64
58
-	ActiveAnon   uint64
59
-	InactiveAnon uint64
60
-	ActiveFile   uint64
61
-	InactiveFile uint64
62
-	Unevictable  uint64
63
-	Mlocked      uint64
57
+	Inactive     *uint64
58
+	ActiveAnon   *uint64
59
+	InactiveAnon *uint64
60
+	ActiveFile   *uint64
61
+	InactiveFile *uint64
62
+	Unevictable  *uint64
63
+	Mlocked      *uint64
64 64
 	// total amount of swap space available
65
-	SwapTotal uint64
65
+	SwapTotal *uint64
66 66
 	// Memory which has been evicted from RAM, and is temporarily
67 67
 	// on the disk
68
-	SwapFree uint64
68
+	SwapFree *uint64
69 69
 	// Memory which is waiting to get written back to the disk
70
-	Dirty uint64
70
+	Dirty *uint64
71 71
 	// Memory which is actively being written back to the disk
72
-	Writeback uint64
72
+	Writeback *uint64
73 73
 	// Non-file backed pages mapped into userspace page tables
74
-	AnonPages uint64
74
+	AnonPages *uint64
75 75
 	// files which have been mapped, such as libraries
76
-	Mapped uint64
77
-	Shmem  uint64
76
+	Mapped *uint64
77
+	Shmem  *uint64
78 78
 	// in-kernel data structures cache
79
-	Slab uint64
79
+	Slab *uint64
80 80
 	// Part of Slab, that might be reclaimed, such as caches
81
-	SReclaimable uint64
81
+	SReclaimable *uint64
82 82
 	// Part of Slab, that cannot be reclaimed on memory pressure
83
-	SUnreclaim  uint64
84
-	KernelStack uint64
83
+	SUnreclaim  *uint64
84
+	KernelStack *uint64
85 85
 	// amount of memory dedicated to the lowest level of page
86 86
 	// tables.
87
-	PageTables uint64
87
+	PageTables *uint64
88 88
 	// NFS pages sent to the server, but not yet committed to
89 89
 	// stable storage
90
-	NFSUnstable uint64
90
+	NFSUnstable *uint64
91 91
 	// Memory used for block device "bounce buffers"
92
-	Bounce uint64
92
+	Bounce *uint64
93 93
 	// Memory used by FUSE for temporary writeback buffers
94
-	WritebackTmp uint64
94
+	WritebackTmp *uint64
95 95
 	// Based on the overcommit ratio ('vm.overcommit_ratio'),
96 96
 	// this is the total amount of  memory currently available to
97 97
 	// be allocated on the system. This limit is only adhered to
... ...
@@ -105,7 +105,7 @@ type Meminfo struct {
105 105
 	// yield a CommitLimit of 7.3G.
106 106
 	// For more details, see the memory overcommit documentation
107 107
 	// in vm/overcommit-accounting.
108
-	CommitLimit uint64
108
+	CommitLimit *uint64
109 109
 	// The amount of memory presently allocated on the system.
110 110
 	// The committed memory is a sum of all of the memory which
111 111
 	// has been allocated by processes, even if it has not been
... ...
@@ -119,27 +119,27 @@ type Meminfo struct {
119 119
 	// This is useful if one needs to guarantee that processes will
120 120
 	// not fail due to lack of memory once that memory has been
121 121
 	// successfully allocated.
122
-	CommittedAS uint64
122
+	CommittedAS *uint64
123 123
 	// total size of vmalloc memory area
124
-	VmallocTotal uint64
124
+	VmallocTotal *uint64
125 125
 	// amount of vmalloc area which is used
126
-	VmallocUsed uint64
126
+	VmallocUsed *uint64
127 127
 	// largest contiguous block of vmalloc area which is free
128
-	VmallocChunk      uint64
129
-	HardwareCorrupted uint64
130
-	AnonHugePages     uint64
131
-	ShmemHugePages    uint64
132
-	ShmemPmdMapped    uint64
133
-	CmaTotal          uint64
134
-	CmaFree           uint64
135
-	HugePagesTotal    uint64
136
-	HugePagesFree     uint64
137
-	HugePagesRsvd     uint64
138
-	HugePagesSurp     uint64
139
-	Hugepagesize      uint64
140
-	DirectMap4k       uint64
141
-	DirectMap2M       uint64
142
-	DirectMap1G       uint64
128
+	VmallocChunk      *uint64
129
+	HardwareCorrupted *uint64
130
+	AnonHugePages     *uint64
131
+	ShmemHugePages    *uint64
132
+	ShmemPmdMapped    *uint64
133
+	CmaTotal          *uint64
134
+	CmaFree           *uint64
135
+	HugePagesTotal    *uint64
136
+	HugePagesFree     *uint64
137
+	HugePagesRsvd     *uint64
138
+	HugePagesSurp     *uint64
139
+	Hugepagesize      *uint64
140
+	DirectMap4k       *uint64
141
+	DirectMap2M       *uint64
142
+	DirectMap1G       *uint64
143 143
 }
144 144
 
145 145
 // Meminfo returns an information about current kernel/system memory statistics.
... ...
@@ -152,7 +152,7 @@ func (fs FS) Meminfo() (Meminfo, error) {
152 152
 
153 153
 	m, err := parseMemInfo(bytes.NewReader(b))
154 154
 	if err != nil {
155
-		return Meminfo{}, fmt.Errorf("failed to parse meminfo: %v", err)
155
+		return Meminfo{}, fmt.Errorf("failed to parse meminfo: %w", err)
156 156
 	}
157 157
 
158 158
 	return *m, nil
... ...
@@ -175,101 +175,101 @@ func parseMemInfo(r io.Reader) (*Meminfo, error) {
175 175
 
176 176
 		switch fields[0] {
177 177
 		case "MemTotal:":
178
-			m.MemTotal = v
178
+			m.MemTotal = &v
179 179
 		case "MemFree:":
180
-			m.MemFree = v
180
+			m.MemFree = &v
181 181
 		case "MemAvailable:":
182
-			m.MemAvailable = v
182
+			m.MemAvailable = &v
183 183
 		case "Buffers:":
184
-			m.Buffers = v
184
+			m.Buffers = &v
185 185
 		case "Cached:":
186
-			m.Cached = v
186
+			m.Cached = &v
187 187
 		case "SwapCached:":
188
-			m.SwapCached = v
188
+			m.SwapCached = &v
189 189
 		case "Active:":
190
-			m.Active = v
190
+			m.Active = &v
191 191
 		case "Inactive:":
192
-			m.Inactive = v
192
+			m.Inactive = &v
193 193
 		case "Active(anon):":
194
-			m.ActiveAnon = v
194
+			m.ActiveAnon = &v
195 195
 		case "Inactive(anon):":
196
-			m.InactiveAnon = v
196
+			m.InactiveAnon = &v
197 197
 		case "Active(file):":
198
-			m.ActiveFile = v
198
+			m.ActiveFile = &v
199 199
 		case "Inactive(file):":
200
-			m.InactiveFile = v
200
+			m.InactiveFile = &v
201 201
 		case "Unevictable:":
202
-			m.Unevictable = v
202
+			m.Unevictable = &v
203 203
 		case "Mlocked:":
204
-			m.Mlocked = v
204
+			m.Mlocked = &v
205 205
 		case "SwapTotal:":
206
-			m.SwapTotal = v
206
+			m.SwapTotal = &v
207 207
 		case "SwapFree:":
208
-			m.SwapFree = v
208
+			m.SwapFree = &v
209 209
 		case "Dirty:":
210
-			m.Dirty = v
210
+			m.Dirty = &v
211 211
 		case "Writeback:":
212
-			m.Writeback = v
212
+			m.Writeback = &v
213 213
 		case "AnonPages:":
214
-			m.AnonPages = v
214
+			m.AnonPages = &v
215 215
 		case "Mapped:":
216
-			m.Mapped = v
216
+			m.Mapped = &v
217 217
 		case "Shmem:":
218
-			m.Shmem = v
218
+			m.Shmem = &v
219 219
 		case "Slab:":
220
-			m.Slab = v
220
+			m.Slab = &v
221 221
 		case "SReclaimable:":
222
-			m.SReclaimable = v
222
+			m.SReclaimable = &v
223 223
 		case "SUnreclaim:":
224
-			m.SUnreclaim = v
224
+			m.SUnreclaim = &v
225 225
 		case "KernelStack:":
226
-			m.KernelStack = v
226
+			m.KernelStack = &v
227 227
 		case "PageTables:":
228
-			m.PageTables = v
228
+			m.PageTables = &v
229 229
 		case "NFS_Unstable:":
230
-			m.NFSUnstable = v
230
+			m.NFSUnstable = &v
231 231
 		case "Bounce:":
232
-			m.Bounce = v
232
+			m.Bounce = &v
233 233
 		case "WritebackTmp:":
234
-			m.WritebackTmp = v
234
+			m.WritebackTmp = &v
235 235
 		case "CommitLimit:":
236
-			m.CommitLimit = v
236
+			m.CommitLimit = &v
237 237
 		case "Committed_AS:":
238
-			m.CommittedAS = v
238
+			m.CommittedAS = &v
239 239
 		case "VmallocTotal:":
240
-			m.VmallocTotal = v
240
+			m.VmallocTotal = &v
241 241
 		case "VmallocUsed:":
242
-			m.VmallocUsed = v
242
+			m.VmallocUsed = &v
243 243
 		case "VmallocChunk:":
244
-			m.VmallocChunk = v
244
+			m.VmallocChunk = &v
245 245
 		case "HardwareCorrupted:":
246
-			m.HardwareCorrupted = v
246
+			m.HardwareCorrupted = &v
247 247
 		case "AnonHugePages:":
248
-			m.AnonHugePages = v
248
+			m.AnonHugePages = &v
249 249
 		case "ShmemHugePages:":
250
-			m.ShmemHugePages = v
250
+			m.ShmemHugePages = &v
251 251
 		case "ShmemPmdMapped:":
252
-			m.ShmemPmdMapped = v
252
+			m.ShmemPmdMapped = &v
253 253
 		case "CmaTotal:":
254
-			m.CmaTotal = v
254
+			m.CmaTotal = &v
255 255
 		case "CmaFree:":
256
-			m.CmaFree = v
256
+			m.CmaFree = &v
257 257
 		case "HugePages_Total:":
258
-			m.HugePagesTotal = v
258
+			m.HugePagesTotal = &v
259 259
 		case "HugePages_Free:":
260
-			m.HugePagesFree = v
260
+			m.HugePagesFree = &v
261 261
 		case "HugePages_Rsvd:":
262
-			m.HugePagesRsvd = v
262
+			m.HugePagesRsvd = &v
263 263
 		case "HugePages_Surp:":
264
-			m.HugePagesSurp = v
264
+			m.HugePagesSurp = &v
265 265
 		case "Hugepagesize:":
266
-			m.Hugepagesize = v
266
+			m.Hugepagesize = &v
267 267
 		case "DirectMap4k:":
268
-			m.DirectMap4k = v
268
+			m.DirectMap4k = &v
269 269
 		case "DirectMap2M:":
270
-			m.DirectMap2M = v
270
+			m.DirectMap2M = &v
271 271
 		case "DirectMap1G:":
272
-			m.DirectMap1G = v
272
+			m.DirectMap1G = &v
273 273
 		}
274 274
 	}
275 275
 
... ...
@@ -77,7 +77,7 @@ func parseMountInfoString(mountString string) (*MountInfo, error) {
77 77
 
78 78
 	mountInfo := strings.Split(mountString, " ")
79 79
 	mountInfoLength := len(mountInfo)
80
-	if mountInfoLength < 11 {
80
+	if mountInfoLength < 10 {
81 81
 		return nil, fmt.Errorf("couldn't find enough fields in mount string: %s", mountString)
82 82
 	}
83 83
 
... ...
@@ -144,7 +144,7 @@ func mountOptionsParseOptionalFields(o []string) (map[string]string, error) {
144 144
 	return optionalFields, nil
145 145
 }
146 146
 
147
-// Parses the mount options, superblock options.
147
+// mountOptionsParser parses the mount options, superblock options.
148 148
 func mountOptionsParser(mountOptions string) map[string]string {
149 149
 	opts := make(map[string]string)
150 150
 	options := strings.Split(mountOptions, ",")
... ...
@@ -161,7 +161,7 @@ func mountOptionsParser(mountOptions string) map[string]string {
161 161
 	return opts
162 162
 }
163 163
 
164
-// Retrieves mountinfo information from `/proc/self/mountinfo`.
164
+// GetMounts retrieves mountinfo information from `/proc/self/mountinfo`.
165 165
 func GetMounts() ([]*MountInfo, error) {
166 166
 	data, err := util.ReadFileNoStat("/proc/self/mountinfo")
167 167
 	if err != nil {
... ...
@@ -170,7 +170,7 @@ func GetMounts() ([]*MountInfo, error) {
170 170
 	return parseMountInfo(data)
171 171
 }
172 172
 
173
-// Retrieves mountinfo information from a processes' `/proc/<pid>/mountinfo`.
173
+// GetProcMounts retrieves mountinfo information from a processes' `/proc/<pid>/mountinfo`.
174 174
 func GetProcMounts(pid int) ([]*MountInfo, error) {
175 175
 	data, err := util.ReadFileNoStat(fmt.Sprintf("/proc/%d/mountinfo", pid))
176 176
 	if err != nil {
... ...
@@ -186,6 +186,8 @@ type NFSOperationStats struct {
186 186
 	CumulativeTotalResponseMilliseconds uint64
187 187
 	// Duration from when a request was enqueued to when it was completely handled.
188 188
 	CumulativeTotalRequestMilliseconds uint64
189
+	// The count of operations that complete with tk_status < 0.  These statuses usually indicate error conditions.
190
+	Errors uint64
189 191
 }
190 192
 
191 193
 // A NFSTransportStats contains statistics for the NFS mount RPC requests and
... ...
@@ -336,12 +338,12 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
336 336
 		if len(ss) == 0 {
337 337
 			break
338 338
 		}
339
-		if len(ss) < 2 {
340
-			return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
341
-		}
342 339
 
343 340
 		switch ss[0] {
344 341
 		case fieldOpts:
342
+			if len(ss) < 2 {
343
+				return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
344
+			}
345 345
 			if stats.Opts == nil {
346 346
 				stats.Opts = map[string]string{}
347 347
 			}
... ...
@@ -354,6 +356,9 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
354 354
 				}
355 355
 			}
356 356
 		case fieldAge:
357
+			if len(ss) < 2 {
358
+				return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
359
+			}
357 360
 			// Age integer is in seconds
358 361
 			d, err := time.ParseDuration(ss[1] + "s")
359 362
 			if err != nil {
... ...
@@ -362,6 +367,9 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
362 362
 
363 363
 			stats.Age = d
364 364
 		case fieldBytes:
365
+			if len(ss) < 2 {
366
+				return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
367
+			}
365 368
 			bstats, err := parseNFSBytesStats(ss[1:])
366 369
 			if err != nil {
367 370
 				return nil, err
... ...
@@ -369,6 +377,9 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
369 369
 
370 370
 			stats.Bytes = *bstats
371 371
 		case fieldEvents:
372
+			if len(ss) < 2 {
373
+				return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
374
+			}
372 375
 			estats, err := parseNFSEventsStats(ss[1:])
373 376
 			if err != nil {
374 377
 				return nil, err
... ...
@@ -494,8 +505,8 @@ func parseNFSEventsStats(ss []string) (*NFSEventsStats, error) {
494 494
 // line is reached.
495 495
 func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
496 496
 	const (
497
-		// Number of expected fields in each per-operation statistics set
498
-		numFields = 9
497
+		// Minimum number of expected fields in each per-operation statistics set
498
+		minFields = 9
499 499
 	)
500 500
 
501 501
 	var ops []NFSOperationStats
... ...
@@ -508,12 +519,12 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
508 508
 			break
509 509
 		}
510 510
 
511
-		if len(ss) != numFields {
511
+		if len(ss) < minFields {
512 512
 			return nil, fmt.Errorf("invalid NFS per-operations stats: %v", ss)
513 513
 		}
514 514
 
515 515
 		// Skip string operation name for integers
516
-		ns := make([]uint64, 0, numFields-1)
516
+		ns := make([]uint64, 0, minFields-1)
517 517
 		for _, st := range ss[1:] {
518 518
 			n, err := strconv.ParseUint(st, 10, 64)
519 519
 			if err != nil {
... ...
@@ -523,7 +534,7 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
523 523
 			ns = append(ns, n)
524 524
 		}
525 525
 
526
-		ops = append(ops, NFSOperationStats{
526
+		opStats := NFSOperationStats{
527 527
 			Operation:                           strings.TrimSuffix(ss[0], ":"),
528 528
 			Requests:                            ns[0],
529 529
 			Transmissions:                       ns[1],
... ...
@@ -533,7 +544,13 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
533 533
 			CumulativeQueueMilliseconds:         ns[5],
534 534
 			CumulativeTotalResponseMilliseconds: ns[6],
535 535
 			CumulativeTotalRequestMilliseconds:  ns[7],
536
-		})
536
+		}
537
+
538
+		if len(ns) > 8 {
539
+			opStats.Errors = ns[8]
540
+		}
541
+
542
+		ops = append(ops, opStats)
537 543
 	}
538 544
 
539 545
 	return ops, s.Err()
... ...
@@ -38,7 +38,7 @@ type ConntrackStatEntry struct {
38 38
 	SearchRestart uint64
39 39
 }
40 40
 
41
-// Retrieves netfilter's conntrack statistics, split by CPU cores
41
+// ConntrackStat retrieves netfilter's conntrack statistics, split by CPU cores
42 42
 func (fs FS) ConntrackStat() ([]ConntrackStatEntry, error) {
43 43
 	return readConntrackStat(fs.proc.Path("net", "stat", "nf_conntrack"))
44 44
 }
... ...
@@ -55,7 +55,7 @@ func readConntrackStat(path string) ([]ConntrackStatEntry, error) {
55 55
 
56 56
 	stat, err := parseConntrackStat(bytes.NewReader(b))
57 57
 	if err != nil {
58
-		return nil, fmt.Errorf("failed to read conntrack stats from %q: %v", path, err)
58
+		return nil, fmt.Errorf("failed to read conntrack stats from %q: %w", path, err)
59 59
 	}
60 60
 
61 61
 	return stat, nil
... ...
@@ -147,7 +147,7 @@ func parseConntrackStatEntry(fields []string) (*ConntrackStatEntry, error) {
147 147
 func parseConntrackStatField(field string) (uint64, error) {
148 148
 	val, err := strconv.ParseUint(field, 16, 64)
149 149
 	if err != nil {
150
-		return 0, fmt.Errorf("couldn't parse \"%s\" field: %s", field, err)
150
+		return 0, fmt.Errorf("couldn't parse %q field: %w", field, err)
151 151
 	}
152 152
 	return val, err
153 153
 }
154 154
new file mode 100644
... ...
@@ -0,0 +1,226 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+package procfs
14
+
15
+import (
16
+	"bufio"
17
+	"encoding/hex"
18
+	"fmt"
19
+	"io"
20
+	"net"
21
+	"os"
22
+	"strconv"
23
+	"strings"
24
+)
25
+
26
+const (
27
+	// readLimit is used by io.LimitReader while reading the content of the
28
+	// /proc/net/udp{,6} files. The number of lines inside such a file is dynamic
29
+	// as each line represents a single used socket.
30
+	// In theory, the number of available sockets is 65535 (2^16 - 1) per IP.
31
+	// With e.g. 150 Byte per line and the maximum number of 65535,
32
+	// the reader needs to handle 150 Byte * 65535 =~ 10 MB for a single IP.
33
+	readLimit = 4294967296 // Byte -> 4 GiB
34
+)
35
+
36
+// this contains generic data structures for both udp and tcp sockets
37
+type (
38
+	// NetIPSocket represents the contents of /proc/net/{t,u}dp{,6} file without the header.
39
+	NetIPSocket []*netIPSocketLine
40
+
41
+	// NetIPSocketSummary provides already computed values like the total queue lengths or
42
+	// the total number of used sockets. In contrast to NetIPSocket it does not collect
43
+	// the parsed lines into a slice.
44
+	NetIPSocketSummary struct {
45
+		// TxQueueLength shows the total queue length of all parsed tx_queue lengths.
46
+		TxQueueLength uint64
47
+		// RxQueueLength shows the total queue length of all parsed rx_queue lengths.
48
+		RxQueueLength uint64
49
+		// UsedSockets shows the total number of parsed lines representing the
50
+		// number of used sockets.
51
+		UsedSockets uint64
52
+	}
53
+
54
+	// netIPSocketLine represents the fields parsed from a single line
55
+	// in /proc/net/{t,u}dp{,6}. Fields which are not used by IPSocket are skipped.
56
+	// For the proc file format details, see https://linux.die.net/man/5/proc.
57
+	netIPSocketLine struct {
58
+		Sl        uint64
59
+		LocalAddr net.IP
60
+		LocalPort uint64
61
+		RemAddr   net.IP
62
+		RemPort   uint64
63
+		St        uint64
64
+		TxQueue   uint64
65
+		RxQueue   uint64
66
+		UID       uint64
67
+		Inode     uint64
68
+	}
69
+)
70
+
71
+func newNetIPSocket(file string) (NetIPSocket, error) {
72
+	f, err := os.Open(file)
73
+	if err != nil {
74
+		return nil, err
75
+	}
76
+	defer f.Close()
77
+
78
+	var netIPSocket NetIPSocket
79
+
80
+	lr := io.LimitReader(f, readLimit)
81
+	s := bufio.NewScanner(lr)
82
+	s.Scan() // skip first line with headers
83
+	for s.Scan() {
84
+		fields := strings.Fields(s.Text())
85
+		line, err := parseNetIPSocketLine(fields)
86
+		if err != nil {
87
+			return nil, err
88
+		}
89
+		netIPSocket = append(netIPSocket, line)
90
+	}
91
+	if err := s.Err(); err != nil {
92
+		return nil, err
93
+	}
94
+	return netIPSocket, nil
95
+}
96
+
97
+// newNetIPSocketSummary creates a new NetIPSocket{,6} from the contents of the given file.
98
+func newNetIPSocketSummary(file string) (*NetIPSocketSummary, error) {
99
+	f, err := os.Open(file)
100
+	if err != nil {
101
+		return nil, err
102
+	}
103
+	defer f.Close()
104
+
105
+	var netIPSocketSummary NetIPSocketSummary
106
+
107
+	lr := io.LimitReader(f, readLimit)
108
+	s := bufio.NewScanner(lr)
109
+	s.Scan() // skip first line with headers
110
+	for s.Scan() {
111
+		fields := strings.Fields(s.Text())
112
+		line, err := parseNetIPSocketLine(fields)
113
+		if err != nil {
114
+			return nil, err
115
+		}
116
+		netIPSocketSummary.TxQueueLength += line.TxQueue
117
+		netIPSocketSummary.RxQueueLength += line.RxQueue
118
+		netIPSocketSummary.UsedSockets++
119
+	}
120
+	if err := s.Err(); err != nil {
121
+		return nil, err
122
+	}
123
+	return &netIPSocketSummary, nil
124
+}
125
+
126
+// the /proc/net/{t,u}dp{,6} files are network byte order for ipv4 and for ipv6 the address is four words consisting of four bytes each. In each of those four words the four bytes are written in reverse order.
127
+
128
+func parseIP(hexIP string) (net.IP, error) {
129
+	var byteIP []byte
130
+	byteIP, err := hex.DecodeString(hexIP)
131
+	if err != nil {
132
+		return nil, fmt.Errorf("cannot parse address field in socket line %q", hexIP)
133
+	}
134
+	switch len(byteIP) {
135
+	case 4:
136
+		return net.IP{byteIP[3], byteIP[2], byteIP[1], byteIP[0]}, nil
137
+	case 16:
138
+		i := net.IP{
139
+			byteIP[3], byteIP[2], byteIP[1], byteIP[0],
140
+			byteIP[7], byteIP[6], byteIP[5], byteIP[4],
141
+			byteIP[11], byteIP[10], byteIP[9], byteIP[8],
142
+			byteIP[15], byteIP[14], byteIP[13], byteIP[12],
143
+		}
144
+		return i, nil
145
+	default:
146
+		return nil, fmt.Errorf("Unable to parse IP %s", hexIP)
147
+	}
148
+}
149
+
150
+// parseNetIPSocketLine parses a single line, represented by a list of fields.
151
+func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) {
152
+	line := &netIPSocketLine{}
153
+	if len(fields) < 10 {
154
+		return nil, fmt.Errorf(
155
+			"cannot parse net socket line as it has less then 10 columns %q",
156
+			strings.Join(fields, " "),
157
+		)
158
+	}
159
+	var err error // parse error
160
+
161
+	// sl
162
+	s := strings.Split(fields[0], ":")
163
+	if len(s) != 2 {
164
+		return nil, fmt.Errorf("cannot parse sl field in socket line %q", fields[0])
165
+	}
166
+
167
+	if line.Sl, err = strconv.ParseUint(s[0], 0, 64); err != nil {
168
+		return nil, fmt.Errorf("cannot parse sl value in socket line: %w", err)
169
+	}
170
+	// local_address
171
+	l := strings.Split(fields[1], ":")
172
+	if len(l) != 2 {
173
+		return nil, fmt.Errorf("cannot parse local_address field in socket line %q", fields[1])
174
+	}
175
+	if line.LocalAddr, err = parseIP(l[0]); err != nil {
176
+		return nil, err
177
+	}
178
+	if line.LocalPort, err = strconv.ParseUint(l[1], 16, 64); err != nil {
179
+		return nil, fmt.Errorf("cannot parse local_address port value in socket line: %w", err)
180
+	}
181
+
182
+	// remote_address
183
+	r := strings.Split(fields[2], ":")
184
+	if len(r) != 2 {
185
+		return nil, fmt.Errorf("cannot parse rem_address field in socket line %q", fields[1])
186
+	}
187
+	if line.RemAddr, err = parseIP(r[0]); err != nil {
188
+		return nil, err
189
+	}
190
+	if line.RemPort, err = strconv.ParseUint(r[1], 16, 64); err != nil {
191
+		return nil, fmt.Errorf("cannot parse rem_address port value in socket line: %w", err)
192
+	}
193
+
194
+	// st
195
+	if line.St, err = strconv.ParseUint(fields[3], 16, 64); err != nil {
196
+		return nil, fmt.Errorf("cannot parse st value in socket line: %w", err)
197
+	}
198
+
199
+	// tx_queue and rx_queue
200
+	q := strings.Split(fields[4], ":")
201
+	if len(q) != 2 {
202
+		return nil, fmt.Errorf(
203
+			"cannot parse tx/rx queues in socket line as it has a missing colon %q",
204
+			fields[4],
205
+		)
206
+	}
207
+	if line.TxQueue, err = strconv.ParseUint(q[0], 16, 64); err != nil {
208
+		return nil, fmt.Errorf("cannot parse tx_queue value in socket line: %w", err)
209
+	}
210
+	if line.RxQueue, err = strconv.ParseUint(q[1], 16, 64); err != nil {
211
+		return nil, fmt.Errorf("cannot parse rx_queue value in socket line: %w", err)
212
+	}
213
+
214
+	// uid
215
+	if line.UID, err = strconv.ParseUint(fields[7], 0, 64); err != nil {
216
+		return nil, fmt.Errorf("cannot parse uid value in socket line: %w", err)
217
+	}
218
+
219
+	// inode
220
+	if line.Inode, err = strconv.ParseUint(fields[9], 0, 64); err != nil {
221
+		return nil, fmt.Errorf("cannot parse inode value in socket line: %w", err)
222
+	}
223
+
224
+	return line, nil
225
+}
0 226
new file mode 100644
... ...
@@ -0,0 +1,180 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+package procfs
14
+
15
+import (
16
+	"bufio"
17
+	"bytes"
18
+	"fmt"
19
+	"strconv"
20
+	"strings"
21
+
22
+	"github.com/prometheus/procfs/internal/util"
23
+)
24
+
25
+// NetProtocolStats stores the contents from /proc/net/protocols
26
+type NetProtocolStats map[string]NetProtocolStatLine
27
+
28
+// NetProtocolStatLine contains a single line parsed from /proc/net/protocols. We
29
+// only care about the first six columns as the rest are not likely to change
30
+// and only serve to provide a set of capabilities for each protocol.
31
+type NetProtocolStatLine struct {
32
+	Name         string // 0 The name of the protocol
33
+	Size         uint64 // 1 The size, in bytes, of a given protocol structure. e.g. sizeof(struct tcp_sock) or sizeof(struct unix_sock)
34
+	Sockets      int64  // 2 Number of sockets in use by this protocol
35
+	Memory       int64  // 3 Number of 4KB pages allocated by all sockets of this protocol
36
+	Pressure     int    // 4 This is either yes, no, or NI (not implemented). For the sake of simplicity we treat NI as not experiencing memory pressure.
37
+	MaxHeader    uint64 // 5 Protocol specific max header size
38
+	Slab         bool   // 6 Indicates whether or not memory is allocated from the SLAB
39
+	ModuleName   string // 7 The name of the module that implemented this protocol or "kernel" if not from a module
40
+	Capabilities NetProtocolCapabilities
41
+}
42
+
43
+// NetProtocolCapabilities contains a list of capabilities for each protocol
44
+type NetProtocolCapabilities struct {
45
+	Close               bool // 8
46
+	Connect             bool // 9
47
+	Disconnect          bool // 10
48
+	Accept              bool // 11
49
+	IoCtl               bool // 12
50
+	Init                bool // 13
51
+	Destroy             bool // 14
52
+	Shutdown            bool // 15
53
+	SetSockOpt          bool // 16
54
+	GetSockOpt          bool // 17
55
+	SendMsg             bool // 18
56
+	RecvMsg             bool // 19
57
+	SendPage            bool // 20
58
+	Bind                bool // 21
59
+	BacklogRcv          bool // 22
60
+	Hash                bool // 23
61
+	UnHash              bool // 24
62
+	GetPort             bool // 25
63
+	EnterMemoryPressure bool // 26
64
+}
65
+
66
+// NetProtocols reads stats from /proc/net/protocols and returns a map of
67
+// PortocolStatLine entries. As of this writing no official Linux Documentation
68
+// exists, however the source is fairly self-explanatory and the format seems
69
+// stable since its introduction in 2.6.12-rc2
70
+// Linux 2.6.12-rc2 - https://elixir.bootlin.com/linux/v2.6.12-rc2/source/net/core/sock.c#L1452
71
+// Linux 5.10 - https://elixir.bootlin.com/linux/v5.10.4/source/net/core/sock.c#L3586
72
+func (fs FS) NetProtocols() (NetProtocolStats, error) {
73
+	data, err := util.ReadFileNoStat(fs.proc.Path("net/protocols"))
74
+	if err != nil {
75
+		return NetProtocolStats{}, err
76
+	}
77
+	return parseNetProtocols(bufio.NewScanner(bytes.NewReader(data)))
78
+}
79
+
80
+func parseNetProtocols(s *bufio.Scanner) (NetProtocolStats, error) {
81
+	nps := NetProtocolStats{}
82
+
83
+	// Skip the header line
84
+	s.Scan()
85
+
86
+	for s.Scan() {
87
+		line, err := nps.parseLine(s.Text())
88
+		if err != nil {
89
+			return NetProtocolStats{}, err
90
+		}
91
+
92
+		nps[line.Name] = *line
93
+	}
94
+	return nps, nil
95
+}
96
+
97
+func (ps NetProtocolStats) parseLine(rawLine string) (*NetProtocolStatLine, error) {
98
+	line := &NetProtocolStatLine{Capabilities: NetProtocolCapabilities{}}
99
+	var err error
100
+	const enabled = "yes"
101
+	const disabled = "no"
102
+
103
+	fields := strings.Fields(rawLine)
104
+	line.Name = fields[0]
105
+	line.Size, err = strconv.ParseUint(fields[1], 10, 64)
106
+	if err != nil {
107
+		return nil, err
108
+	}
109
+	line.Sockets, err = strconv.ParseInt(fields[2], 10, 64)
110
+	if err != nil {
111
+		return nil, err
112
+	}
113
+	line.Memory, err = strconv.ParseInt(fields[3], 10, 64)
114
+	if err != nil {
115
+		return nil, err
116
+	}
117
+	if fields[4] == enabled {
118
+		line.Pressure = 1
119
+	} else if fields[4] == disabled {
120
+		line.Pressure = 0
121
+	} else {
122
+		line.Pressure = -1
123
+	}
124
+	line.MaxHeader, err = strconv.ParseUint(fields[5], 10, 64)
125
+	if err != nil {
126
+		return nil, err
127
+	}
128
+	if fields[6] == enabled {
129
+		line.Slab = true
130
+	} else if fields[6] == disabled {
131
+		line.Slab = false
132
+	} else {
133
+		return nil, fmt.Errorf("unable to parse capability for protocol: %s", line.Name)
134
+	}
135
+	line.ModuleName = fields[7]
136
+
137
+	err = line.Capabilities.parseCapabilities(fields[8:])
138
+	if err != nil {
139
+		return nil, err
140
+	}
141
+
142
+	return line, nil
143
+}
144
+
145
+func (pc *NetProtocolCapabilities) parseCapabilities(capabilities []string) error {
146
+	// The capabilities are all bools so we can loop over to map them
147
+	capabilityFields := [...]*bool{
148
+		&pc.Close,
149
+		&pc.Connect,
150
+		&pc.Disconnect,
151
+		&pc.Accept,
152
+		&pc.IoCtl,
153
+		&pc.Init,
154
+		&pc.Destroy,
155
+		&pc.Shutdown,
156
+		&pc.SetSockOpt,
157
+		&pc.GetSockOpt,
158
+		&pc.SendMsg,
159
+		&pc.RecvMsg,
160
+		&pc.SendPage,
161
+		&pc.Bind,
162
+		&pc.BacklogRcv,
163
+		&pc.Hash,
164
+		&pc.UnHash,
165
+		&pc.GetPort,
166
+		&pc.EnterMemoryPressure,
167
+	}
168
+
169
+	for i := 0; i < len(capabilities); i++ {
170
+		if capabilities[i] == "y" {
171
+			*capabilityFields[i] = true
172
+		} else if capabilities[i] == "n" {
173
+			*capabilityFields[i] = false
174
+		} else {
175
+			return fmt.Errorf("unable to parse capability block for protocol: position %d", i)
176
+		}
177
+	}
178
+	return nil
179
+}
... ...
@@ -70,7 +70,7 @@ func readSockstat(name string) (*NetSockstat, error) {
70 70
 
71 71
 	stat, err := parseSockstat(bytes.NewReader(b))
72 72
 	if err != nil {
73
-		return nil, fmt.Errorf("failed to read sockstats from %q: %v", name, err)
73
+		return nil, fmt.Errorf("failed to read sockstats from %q: %w", name, err)
74 74
 	}
75 75
 
76 76
 	return stat, nil
... ...
@@ -90,7 +90,7 @@ func parseSockstat(r io.Reader) (*NetSockstat, error) {
90 90
 		// The remaining fields are key/value pairs.
91 91
 		kvs, err := parseSockstatKVs(fields[1:])
92 92
 		if err != nil {
93
-			return nil, fmt.Errorf("error parsing sockstat key/value pairs from %q: %v", s.Text(), err)
93
+			return nil, fmt.Errorf("error parsing sockstat key/value pairs from %q: %w", s.Text(), err)
94 94
 		}
95 95
 
96 96
 		// The first field is the protocol. We must trim its colon suffix.
... ...
@@ -51,7 +51,7 @@ func (fs FS) NetSoftnetStat() ([]SoftnetStat, error) {
51 51
 
52 52
 	entries, err := parseSoftnet(bytes.NewReader(b))
53 53
 	if err != nil {
54
-		return nil, fmt.Errorf("failed to parse /proc/net/softnet_stat: %v", err)
54
+		return nil, fmt.Errorf("failed to parse /proc/net/softnet_stat: %w", err)
55 55
 	}
56 56
 
57 57
 	return entries, nil
58 58
new file mode 100644
... ...
@@ -0,0 +1,64 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+package procfs
14
+
15
+type (
16
+	// NetTCP represents the contents of /proc/net/tcp{,6} file without the header.
17
+	NetTCP []*netIPSocketLine
18
+
19
+	// NetTCPSummary provides already computed values like the total queue lengths or
20
+	// the total number of used sockets. In contrast to NetTCP it does not collect
21
+	// the parsed lines into a slice.
22
+	NetTCPSummary NetIPSocketSummary
23
+)
24
+
25
+// NetTCP returns the IPv4 kernel/networking statistics for TCP datagrams
26
+// read from /proc/net/tcp.
27
+func (fs FS) NetTCP() (NetTCP, error) {
28
+	return newNetTCP(fs.proc.Path("net/tcp"))
29
+}
30
+
31
+// NetTCP6 returns the IPv6 kernel/networking statistics for TCP datagrams
32
+// read from /proc/net/tcp6.
33
+func (fs FS) NetTCP6() (NetTCP, error) {
34
+	return newNetTCP(fs.proc.Path("net/tcp6"))
35
+}
36
+
37
+// NetTCPSummary returns already computed statistics like the total queue lengths
38
+// for TCP datagrams read from /proc/net/tcp.
39
+func (fs FS) NetTCPSummary() (*NetTCPSummary, error) {
40
+	return newNetTCPSummary(fs.proc.Path("net/tcp"))
41
+}
42
+
43
+// NetTCP6Summary returns already computed statistics like the total queue lengths
44
+// for TCP datagrams read from /proc/net/tcp6.
45
+func (fs FS) NetTCP6Summary() (*NetTCPSummary, error) {
46
+	return newNetTCPSummary(fs.proc.Path("net/tcp6"))
47
+}
48
+
49
+// newNetTCP creates a new NetTCP{,6} from the contents of the given file.
50
+func newNetTCP(file string) (NetTCP, error) {
51
+	n, err := newNetIPSocket(file)
52
+	n1 := NetTCP(n)
53
+	return n1, err
54
+}
55
+
56
+func newNetTCPSummary(file string) (*NetTCPSummary, error) {
57
+	n, err := newNetIPSocketSummary(file)
58
+	if n == nil {
59
+		return nil, err
60
+	}
61
+	n1 := NetTCPSummary(*n)
62
+	return &n1, err
63
+}
... ...
@@ -13,58 +13,14 @@
13 13
 
14 14
 package procfs
15 15
 
16
-import (
17
-	"bufio"
18
-	"encoding/hex"
19
-	"fmt"
20
-	"io"
21
-	"net"
22
-	"os"
23
-	"strconv"
24
-	"strings"
25
-)
26
-
27
-const (
28
-	// readLimit is used by io.LimitReader while reading the content of the
29
-	// /proc/net/udp{,6} files. The number of lines inside such a file is dynamic
30
-	// as each line represents a single used socket.
31
-	// In theory, the number of available sockets is 65535 (2^16 - 1) per IP.
32
-	// With e.g. 150 Byte per line and the maximum number of 65535,
33
-	// the reader needs to handle 150 Byte * 65535 =~ 10 MB for a single IP.
34
-	readLimit = 4294967296 // Byte -> 4 GiB
35
-)
36
-
37 16
 type (
38 17
 	// NetUDP represents the contents of /proc/net/udp{,6} file without the header.
39
-	NetUDP []*netUDPLine
18
+	NetUDP []*netIPSocketLine
40 19
 
41 20
 	// NetUDPSummary provides already computed values like the total queue lengths or
42 21
 	// the total number of used sockets. In contrast to NetUDP it does not collect
43 22
 	// the parsed lines into a slice.
44
-	NetUDPSummary struct {
45
-		// TxQueueLength shows the total queue length of all parsed tx_queue lengths.
46
-		TxQueueLength uint64
47
-		// RxQueueLength shows the total queue length of all parsed rx_queue lengths.
48
-		RxQueueLength uint64
49
-		// UsedSockets shows the total number of parsed lines representing the
50
-		// number of used sockets.
51
-		UsedSockets uint64
52
-	}
53
-
54
-	// netUDPLine represents the fields parsed from a single line
55
-	// in /proc/net/udp{,6}. Fields which are not used by UDP are skipped.
56
-	// For the proc file format details, see https://linux.die.net/man/5/proc.
57
-	netUDPLine struct {
58
-		Sl        uint64
59
-		LocalAddr net.IP
60
-		LocalPort uint64
61
-		RemAddr   net.IP
62
-		RemPort   uint64
63
-		St        uint64
64
-		TxQueue   uint64
65
-		RxQueue   uint64
66
-		UID       uint64
67
-	}
23
+	NetUDPSummary NetIPSocketSummary
68 24
 )
69 25
 
70 26
 // NetUDP returns the IPv4 kernel/networking statistics for UDP datagrams
... ...
@@ -93,137 +49,16 @@ func (fs FS) NetUDP6Summary() (*NetUDPSummary, error) {
93 93
 
94 94
 // newNetUDP creates a new NetUDP{,6} from the contents of the given file.
95 95
 func newNetUDP(file string) (NetUDP, error) {
96
-	f, err := os.Open(file)
97
-	if err != nil {
98
-		return nil, err
99
-	}
100
-	defer f.Close()
101
-
102
-	netUDP := NetUDP{}
103
-
104
-	lr := io.LimitReader(f, readLimit)
105
-	s := bufio.NewScanner(lr)
106
-	s.Scan() // skip first line with headers
107
-	for s.Scan() {
108
-		fields := strings.Fields(s.Text())
109
-		line, err := parseNetUDPLine(fields)
110
-		if err != nil {
111
-			return nil, err
112
-		}
113
-		netUDP = append(netUDP, line)
114
-	}
115
-	if err := s.Err(); err != nil {
116
-		return nil, err
117
-	}
118
-	return netUDP, nil
96
+	n, err := newNetIPSocket(file)
97
+	n1 := NetUDP(n)
98
+	return n1, err
119 99
 }
120 100
 
121
-// newNetUDPSummary creates a new NetUDP{,6} from the contents of the given file.
122 101
 func newNetUDPSummary(file string) (*NetUDPSummary, error) {
123
-	f, err := os.Open(file)
124
-	if err != nil {
125
-		return nil, err
126
-	}
127
-	defer f.Close()
128
-
129
-	netUDPSummary := &NetUDPSummary{}
130
-
131
-	lr := io.LimitReader(f, readLimit)
132
-	s := bufio.NewScanner(lr)
133
-	s.Scan() // skip first line with headers
134
-	for s.Scan() {
135
-		fields := strings.Fields(s.Text())
136
-		line, err := parseNetUDPLine(fields)
137
-		if err != nil {
138
-			return nil, err
139
-		}
140
-		netUDPSummary.TxQueueLength += line.TxQueue
141
-		netUDPSummary.RxQueueLength += line.RxQueue
142
-		netUDPSummary.UsedSockets++
143
-	}
144
-	if err := s.Err(); err != nil {
102
+	n, err := newNetIPSocketSummary(file)
103
+	if n == nil {
145 104
 		return nil, err
146 105
 	}
147
-	return netUDPSummary, nil
148
-}
149
-
150
-// parseNetUDPLine parses a single line, represented by a list of fields.
151
-func parseNetUDPLine(fields []string) (*netUDPLine, error) {
152
-	line := &netUDPLine{}
153
-	if len(fields) < 8 {
154
-		return nil, fmt.Errorf(
155
-			"cannot parse net udp socket line as it has less then 8 columns: %s",
156
-			strings.Join(fields, " "),
157
-		)
158
-	}
159
-	var err error // parse error
160
-
161
-	// sl
162
-	s := strings.Split(fields[0], ":")
163
-	if len(s) != 2 {
164
-		return nil, fmt.Errorf(
165
-			"cannot parse sl field in udp socket line: %s", fields[0])
166
-	}
167
-
168
-	if line.Sl, err = strconv.ParseUint(s[0], 0, 64); err != nil {
169
-		return nil, fmt.Errorf("cannot parse sl value in udp socket line: %s", err)
170
-	}
171
-	// local_address
172
-	l := strings.Split(fields[1], ":")
173
-	if len(l) != 2 {
174
-		return nil, fmt.Errorf(
175
-			"cannot parse local_address field in udp socket line: %s", fields[1])
176
-	}
177
-	if line.LocalAddr, err = hex.DecodeString(l[0]); err != nil {
178
-		return nil, fmt.Errorf(
179
-			"cannot parse local_address value in udp socket line: %s", err)
180
-	}
181
-	if line.LocalPort, err = strconv.ParseUint(l[1], 16, 64); err != nil {
182
-		return nil, fmt.Errorf(
183
-			"cannot parse local_address port value in udp socket line: %s", err)
184
-	}
185
-
186
-	// remote_address
187
-	r := strings.Split(fields[2], ":")
188
-	if len(r) != 2 {
189
-		return nil, fmt.Errorf(
190
-			"cannot parse rem_address field in udp socket line: %s", fields[1])
191
-	}
192
-	if line.RemAddr, err = hex.DecodeString(r[0]); err != nil {
193
-		return nil, fmt.Errorf(
194
-			"cannot parse rem_address value in udp socket line: %s", err)
195
-	}
196
-	if line.RemPort, err = strconv.ParseUint(r[1], 16, 64); err != nil {
197
-		return nil, fmt.Errorf(
198
-			"cannot parse rem_address port value in udp socket line: %s", err)
199
-	}
200
-
201
-	// st
202
-	if line.St, err = strconv.ParseUint(fields[3], 16, 64); err != nil {
203
-		return nil, fmt.Errorf(
204
-			"cannot parse st value in udp socket line: %s", err)
205
-	}
206
-
207
-	// tx_queue and rx_queue
208
-	q := strings.Split(fields[4], ":")
209
-	if len(q) != 2 {
210
-		return nil, fmt.Errorf(
211
-			"cannot parse tx/rx queues in udp socket line as it has a missing colon: %s",
212
-			fields[4],
213
-		)
214
-	}
215
-	if line.TxQueue, err = strconv.ParseUint(q[0], 16, 64); err != nil {
216
-		return nil, fmt.Errorf("cannot parse tx_queue value in udp socket line: %s", err)
217
-	}
218
-	if line.RxQueue, err = strconv.ParseUint(q[1], 16, 64); err != nil {
219
-		return nil, fmt.Errorf("cannot parse rx_queue value in udp socket line: %s", err)
220
-	}
221
-
222
-	// uid
223
-	if line.UID, err = strconv.ParseUint(fields[7], 0, 64); err != nil {
224
-		return nil, fmt.Errorf(
225
-			"cannot parse uid value in udp socket line: %s", err)
226
-	}
227
-
228
-	return line, nil
106
+	n1 := NetUDPSummary(*n)
107
+	return &n1, err
229 108
 }
... ...
@@ -108,14 +108,14 @@ func parseNetUNIX(r io.Reader) (*NetUNIX, error) {
108 108
 		line := s.Text()
109 109
 		item, err := nu.parseLine(line, hasInode, minFields)
110 110
 		if err != nil {
111
-			return nil, fmt.Errorf("failed to parse /proc/net/unix data %q: %v", line, err)
111
+			return nil, fmt.Errorf("failed to parse /proc/net/unix data %q: %w", line, err)
112 112
 		}
113 113
 
114 114
 		nu.Rows = append(nu.Rows, item)
115 115
 	}
116 116
 
117 117
 	if err := s.Err(); err != nil {
118
-		return nil, fmt.Errorf("failed to scan /proc/net/unix data: %v", err)
118
+		return nil, fmt.Errorf("failed to scan /proc/net/unix data: %w", err)
119 119
 	}
120 120
 
121 121
 	return &nu, nil
... ...
@@ -136,29 +136,29 @@ func (u *NetUNIX) parseLine(line string, hasInode bool, min int) (*NetUNIXLine,
136 136
 
137 137
 	users, err := u.parseUsers(fields[1])
138 138
 	if err != nil {
139
-		return nil, fmt.Errorf("failed to parse ref count(%s): %v", fields[1], err)
139
+		return nil, fmt.Errorf("failed to parse ref count %q: %w", fields[1], err)
140 140
 	}
141 141
 
142 142
 	flags, err := u.parseFlags(fields[3])
143 143
 	if err != nil {
144
-		return nil, fmt.Errorf("failed to parse flags(%s): %v", fields[3], err)
144
+		return nil, fmt.Errorf("failed to parse flags %q: %w", fields[3], err)
145 145
 	}
146 146
 
147 147
 	typ, err := u.parseType(fields[4])
148 148
 	if err != nil {
149
-		return nil, fmt.Errorf("failed to parse type(%s): %v", fields[4], err)
149
+		return nil, fmt.Errorf("failed to parse type %q: %w", fields[4], err)
150 150
 	}
151 151
 
152 152
 	state, err := u.parseState(fields[5])
153 153
 	if err != nil {
154
-		return nil, fmt.Errorf("failed to parse state(%s): %v", fields[5], err)
154
+		return nil, fmt.Errorf("failed to parse state %q: %w", fields[5], err)
155 155
 	}
156 156
 
157 157
 	var inode uint64
158 158
 	if hasInode {
159 159
 		inode, err = u.parseInode(fields[6])
160 160
 		if err != nil {
161
-			return nil, fmt.Errorf("failed to parse inode(%s): %v", fields[6], err)
161
+			return nil, fmt.Errorf("failed to parse inode %q: %w", fields[6], err)
162 162
 		}
163 163
 	}
164 164
 
165 165
new file mode 100644
... ...
@@ -0,0 +1,68 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+package procfs
14
+
15
+import (
16
+	"bufio"
17
+	"os"
18
+	"path/filepath"
19
+	"strconv"
20
+	"strings"
21
+)
22
+
23
+// NetStat contains statistics for all the counters from one file
24
+type NetStat struct {
25
+	Filename string
26
+	Stats    map[string][]uint64
27
+}
28
+
29
+// NetStat retrieves stats from /proc/net/stat/
30
+func (fs FS) NetStat() ([]NetStat, error) {
31
+	statFiles, err := filepath.Glob(fs.proc.Path("net/stat/*"))
32
+	if err != nil {
33
+		return nil, err
34
+	}
35
+
36
+	var netStatsTotal []NetStat
37
+
38
+	for _, filePath := range statFiles {
39
+		file, err := os.Open(filePath)
40
+		if err != nil {
41
+			return nil, err
42
+		}
43
+
44
+		netStatFile := NetStat{
45
+			Filename: filepath.Base(filePath),
46
+			Stats:    make(map[string][]uint64),
47
+		}
48
+		scanner := bufio.NewScanner(file)
49
+		scanner.Scan()
50
+		// First string is always a header for stats
51
+		var headers []string
52
+		headers = append(headers, strings.Fields(scanner.Text())...)
53
+
54
+		// Other strings represent per-CPU counters
55
+		for scanner.Scan() {
56
+			for num, counter := range strings.Fields(scanner.Text()) {
57
+				value, err := strconv.ParseUint(counter, 16, 32)
58
+				if err != nil {
59
+					return nil, err
60
+				}
61
+				netStatFile.Stats[headers[num]] = append(netStatFile.Stats[headers[num]], value)
62
+			}
63
+		}
64
+		netStatsTotal = append(netStatsTotal, netStatFile)
65
+	}
66
+	return netStatsTotal, nil
67
+}
... ...
@@ -105,7 +105,7 @@ func (fs FS) AllProcs() (Procs, error) {
105 105
 
106 106
 	names, err := d.Readdirnames(-1)
107 107
 	if err != nil {
108
-		return Procs{}, fmt.Errorf("could not read %s: %s", d.Name(), err)
108
+		return Procs{}, fmt.Errorf("could not read %q: %w", d.Name(), err)
109 109
 	}
110 110
 
111 111
 	p := Procs{}
... ...
@@ -134,6 +134,27 @@ func (p Proc) CmdLine() ([]string, error) {
134 134
 	return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil
135 135
 }
136 136
 
137
+// Wchan returns the wchan (wait channel) of a process.
138
+func (p Proc) Wchan() (string, error) {
139
+	f, err := os.Open(p.path("wchan"))
140
+	if err != nil {
141
+		return "", err
142
+	}
143
+	defer f.Close()
144
+
145
+	data, err := ioutil.ReadAll(f)
146
+	if err != nil {
147
+		return "", err
148
+	}
149
+
150
+	wchan := string(data)
151
+	if wchan == "" || wchan == "0" {
152
+		return "", nil
153
+	}
154
+
155
+	return wchan, nil
156
+}
157
+
137 158
 // Comm returns the command name of a process.
138 159
 func (p Proc) Comm() (string, error) {
139 160
 	data, err := util.ReadFileNoStat(p.path("comm"))
... ...
@@ -185,7 +206,7 @@ func (p Proc) FileDescriptors() ([]uintptr, error) {
185 185
 	for i, n := range names {
186 186
 		fd, err := strconv.ParseInt(n, 10, 32)
187 187
 		if err != nil {
188
-			return nil, fmt.Errorf("could not parse fd %s: %s", n, err)
188
+			return nil, fmt.Errorf("could not parse fd %q: %w", n, err)
189 189
 		}
190 190
 		fds[i] = uintptr(fd)
191 191
 	}
... ...
@@ -257,7 +278,7 @@ func (p Proc) fileDescriptors() ([]string, error) {
257 257
 
258 258
 	names, err := d.Readdirnames(-1)
259 259
 	if err != nil {
260
-		return nil, fmt.Errorf("could not read %s: %s", d.Name(), err)
260
+		return nil, fmt.Errorf("could not read %q: %w", d.Name(), err)
261 261
 	}
262 262
 
263 263
 	return names, nil
264 264
new file mode 100644
... ...
@@ -0,0 +1,98 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+package procfs
14
+
15
+import (
16
+	"bufio"
17
+	"bytes"
18
+	"fmt"
19
+	"strconv"
20
+	"strings"
21
+
22
+	"github.com/prometheus/procfs/internal/util"
23
+)
24
+
25
+// Cgroup models one line from /proc/[pid]/cgroup. Each Cgroup struct describes the the placement of a PID inside a
26
+// specific control hierarchy. The kernel has two cgroup APIs, v1 and v2. v1 has one hierarchy per available resource
27
+// controller, while v2 has one unified hierarchy shared by all controllers. Regardless of v1 or v2, all hierarchies
28
+// contain all running processes, so the question answerable with a Cgroup struct is 'where is this process in
29
+// this hierarchy' (where==what path on the specific cgroupfs). By prefixing this path with the mount point of
30
+// *this specific* hierarchy, you can locate the relevant pseudo-files needed to read/set the data for this PID
31
+// in this hierarchy
32
+//
33
+// Also see http://man7.org/linux/man-pages/man7/cgroups.7.html
34
+type Cgroup struct {
35
+	// HierarchyID that can be matched to a named hierarchy using /proc/cgroups. Cgroups V2 only has one
36
+	// hierarchy, so HierarchyID is always 0. For cgroups v1 this is a unique ID number
37
+	HierarchyID int
38
+	// Controllers using this hierarchy of processes. Controllers are also known as subsystems. For
39
+	// Cgroups V2 this may be empty, as all active controllers use the same hierarchy
40
+	Controllers []string
41
+	// Path of this control group, relative to the mount point of the cgroupfs representing this specific
42
+	// hierarchy
43
+	Path string
44
+}
45
+
46
+// parseCgroupString parses each line of the /proc/[pid]/cgroup file
47
+// Line format is hierarchyID:[controller1,controller2]:path
48
+func parseCgroupString(cgroupStr string) (*Cgroup, error) {
49
+	var err error
50
+
51
+	fields := strings.SplitN(cgroupStr, ":", 3)
52
+	if len(fields) < 3 {
53
+		return nil, fmt.Errorf("at least 3 fields required, found %d fields in cgroup string: %s", len(fields), cgroupStr)
54
+	}
55
+
56
+	cgroup := &Cgroup{
57
+		Path:        fields[2],
58
+		Controllers: nil,
59
+	}
60
+	cgroup.HierarchyID, err = strconv.Atoi(fields[0])
61
+	if err != nil {
62
+		return nil, fmt.Errorf("failed to parse hierarchy ID")
63
+	}
64
+	if fields[1] != "" {
65
+		ssNames := strings.Split(fields[1], ",")
66
+		cgroup.Controllers = append(cgroup.Controllers, ssNames...)
67
+	}
68
+	return cgroup, nil
69
+}
70
+
71
+// parseCgroups reads each line of the /proc/[pid]/cgroup file
72
+func parseCgroups(data []byte) ([]Cgroup, error) {
73
+	var cgroups []Cgroup
74
+	scanner := bufio.NewScanner(bytes.NewReader(data))
75
+	for scanner.Scan() {
76
+		mountString := scanner.Text()
77
+		parsedMounts, err := parseCgroupString(mountString)
78
+		if err != nil {
79
+			return nil, err
80
+		}
81
+		cgroups = append(cgroups, *parsedMounts)
82
+	}
83
+
84
+	err := scanner.Err()
85
+	return cgroups, err
86
+}
87
+
88
+// Cgroups reads from /proc/<pid>/cgroups and returns a []*Cgroup struct locating this PID in each process
89
+// control hierarchy running on this system. On every system (v1 and v2), all hierarchies contain all processes,
90
+// so the len of the returned struct is equal to the number of active hierarchies on this system
91
+func (p Proc) Cgroups() ([]Cgroup, error) {
92
+	data, err := util.ReadFileNoStat(p.path("cgroup"))
93
+	if err != nil {
94
+		return nil, err
95
+	}
96
+	return parseCgroups(data)
97
+}
... ...
@@ -16,7 +16,7 @@ package procfs
16 16
 import (
17 17
 	"bufio"
18 18
 	"bytes"
19
-	"errors"
19
+	"fmt"
20 20
 	"regexp"
21 21
 
22 22
 	"github.com/prometheus/procfs/internal/util"
... ...
@@ -41,7 +41,7 @@ type ProcFDInfo struct {
41 41
 	Flags string
42 42
 	// Mount point ID
43 43
 	MntID string
44
-	// List of inotify lines (structed) in the fdinfo file (kernel 3.8+ only)
44
+	// List of inotify lines (structured) in the fdinfo file (kernel 3.8+ only)
45 45
 	InotifyInfos []InotifyInfo
46 46
 }
47 47
 
... ...
@@ -112,7 +112,7 @@ func parseInotifyInfo(line string) (*InotifyInfo, error) {
112 112
 		}
113 113
 		return i, nil
114 114
 	}
115
-	return nil, errors.New("invalid inode entry: " + line)
115
+	return nil, fmt.Errorf("invalid inode entry: %q", line)
116 116
 }
117 117
 
118 118
 // ProcFDInfos represents a list of ProcFDInfo structs.
... ...
@@ -26,55 +26,55 @@ import (
26 26
 // http://man7.org/linux/man-pages/man2/getrlimit.2.html.
27 27
 type ProcLimits struct {
28 28
 	// CPU time limit in seconds.
29
-	CPUTime int64
29
+	CPUTime uint64
30 30
 	// Maximum size of files that the process may create.
31
-	FileSize int64
31
+	FileSize uint64
32 32
 	// Maximum size of the process's data segment (initialized data,
33 33
 	// uninitialized data, and heap).
34
-	DataSize int64
34
+	DataSize uint64
35 35
 	// Maximum size of the process stack in bytes.
36
-	StackSize int64
36
+	StackSize uint64
37 37
 	// Maximum size of a core file.
38
-	CoreFileSize int64
38
+	CoreFileSize uint64
39 39
 	// Limit of the process's resident set in pages.
40
-	ResidentSet int64
40
+	ResidentSet uint64
41 41
 	// Maximum number of processes that can be created for the real user ID of
42 42
 	// the calling process.
43
-	Processes int64
43
+	Processes uint64
44 44
 	// Value one greater than the maximum file descriptor number that can be
45 45
 	// opened by this process.
46
-	OpenFiles int64
46
+	OpenFiles uint64
47 47
 	// Maximum number of bytes of memory that may be locked into RAM.
48
-	LockedMemory int64
48
+	LockedMemory uint64
49 49
 	// Maximum size of the process's virtual memory address space in bytes.
50
-	AddressSpace int64
50
+	AddressSpace uint64
51 51
 	// Limit on the combined number of flock(2) locks and fcntl(2) leases that
52 52
 	// this process may establish.
53
-	FileLocks int64
53
+	FileLocks uint64
54 54
 	// Limit of signals that may be queued for the real user ID of the calling
55 55
 	// process.
56
-	PendingSignals int64
56
+	PendingSignals uint64
57 57
 	// Limit on the number of bytes that can be allocated for POSIX message
58 58
 	// queues for the real user ID of the calling process.
59
-	MsqqueueSize int64
59
+	MsqqueueSize uint64
60 60
 	// Limit of the nice priority set using setpriority(2) or nice(2).
61
-	NicePriority int64
61
+	NicePriority uint64
62 62
 	// Limit of the real-time priority set using sched_setscheduler(2) or
63 63
 	// sched_setparam(2).
64
-	RealtimePriority int64
64
+	RealtimePriority uint64
65 65
 	// Limit (in microseconds) on the amount of CPU time that a process
66 66
 	// scheduled under a real-time scheduling policy may consume without making
67 67
 	// a blocking system call.
68
-	RealtimeTimeout int64
68
+	RealtimeTimeout uint64
69 69
 }
70 70
 
71 71
 const (
72
-	limitsFields    = 3
72
+	limitsFields    = 4
73 73
 	limitsUnlimited = "unlimited"
74 74
 )
75 75
 
76 76
 var (
77
-	limitsDelimiter = regexp.MustCompile("  +")
77
+	limitsMatch = regexp.MustCompile(`(Max \w+\s{0,1}?\w*\s{0,1}\w*)\s{2,}(\w+)\s+(\w+)`)
78 78
 )
79 79
 
80 80
 // NewLimits returns the current soft limits of the process.
... ...
@@ -96,46 +96,49 @@ func (p Proc) Limits() (ProcLimits, error) {
96 96
 		l = ProcLimits{}
97 97
 		s = bufio.NewScanner(f)
98 98
 	)
99
+
100
+	s.Scan() // Skip limits header
101
+
99 102
 	for s.Scan() {
100
-		fields := limitsDelimiter.Split(s.Text(), limitsFields)
103
+		//fields := limitsMatch.Split(s.Text(), limitsFields)
104
+		fields := limitsMatch.FindStringSubmatch(s.Text())
101 105
 		if len(fields) != limitsFields {
102
-			return ProcLimits{}, fmt.Errorf(
103
-				"couldn't parse %s line %s", f.Name(), s.Text())
106
+			return ProcLimits{}, fmt.Errorf("couldn't parse %q line %q", f.Name(), s.Text())
104 107
 		}
105 108
 
106
-		switch fields[0] {
109
+		switch fields[1] {
107 110
 		case "Max cpu time":
108
-			l.CPUTime, err = parseInt(fields[1])
111
+			l.CPUTime, err = parseUint(fields[2])
109 112
 		case "Max file size":
110
-			l.FileSize, err = parseInt(fields[1])
113
+			l.FileSize, err = parseUint(fields[2])
111 114
 		case "Max data size":
112
-			l.DataSize, err = parseInt(fields[1])
115
+			l.DataSize, err = parseUint(fields[2])
113 116
 		case "Max stack size":
114
-			l.StackSize, err = parseInt(fields[1])
117
+			l.StackSize, err = parseUint(fields[2])
115 118
 		case "Max core file size":
116
-			l.CoreFileSize, err = parseInt(fields[1])
119
+			l.CoreFileSize, err = parseUint(fields[2])
117 120
 		case "Max resident set":
118
-			l.ResidentSet, err = parseInt(fields[1])
121
+			l.ResidentSet, err = parseUint(fields[2])
119 122
 		case "Max processes":
120
-			l.Processes, err = parseInt(fields[1])
123
+			l.Processes, err = parseUint(fields[2])
121 124
 		case "Max open files":
122
-			l.OpenFiles, err = parseInt(fields[1])
125
+			l.OpenFiles, err = parseUint(fields[2])
123 126
 		case "Max locked memory":
124
-			l.LockedMemory, err = parseInt(fields[1])
127
+			l.LockedMemory, err = parseUint(fields[2])
125 128
 		case "Max address space":
126
-			l.AddressSpace, err = parseInt(fields[1])
129
+			l.AddressSpace, err = parseUint(fields[2])
127 130
 		case "Max file locks":
128
-			l.FileLocks, err = parseInt(fields[1])
131
+			l.FileLocks, err = parseUint(fields[2])
129 132
 		case "Max pending signals":
130
-			l.PendingSignals, err = parseInt(fields[1])
133
+			l.PendingSignals, err = parseUint(fields[2])
131 134
 		case "Max msgqueue size":
132
-			l.MsqqueueSize, err = parseInt(fields[1])
135
+			l.MsqqueueSize, err = parseUint(fields[2])
133 136
 		case "Max nice priority":
134
-			l.NicePriority, err = parseInt(fields[1])
137
+			l.NicePriority, err = parseUint(fields[2])
135 138
 		case "Max realtime priority":
136
-			l.RealtimePriority, err = parseInt(fields[1])
139
+			l.RealtimePriority, err = parseUint(fields[2])
137 140
 		case "Max realtime timeout":
138
-			l.RealtimeTimeout, err = parseInt(fields[1])
141
+			l.RealtimeTimeout, err = parseUint(fields[2])
139 142
 		}
140 143
 		if err != nil {
141 144
 			return ProcLimits{}, err
... ...
@@ -145,13 +148,13 @@ func (p Proc) Limits() (ProcLimits, error) {
145 145
 	return l, s.Err()
146 146
 }
147 147
 
148
-func parseInt(s string) (int64, error) {
148
+func parseUint(s string) (uint64, error) {
149 149
 	if s == limitsUnlimited {
150
-		return -1, nil
150
+		return 18446744073709551615, nil
151 151
 	}
152
-	i, err := strconv.ParseInt(s, 10, 64)
152
+	i, err := strconv.ParseUint(s, 10, 64)
153 153
 	if err != nil {
154
-		return 0, fmt.Errorf("couldn't parse value %s: %s", s, err)
154
+		return 0, fmt.Errorf("couldn't parse value %q: %w", s, err)
155 155
 	}
156 156
 	return i, nil
157 157
 }
... ...
@@ -11,7 +11,7 @@
11 11
 // See the License for the specific language governing permissions and
12 12
 // limitations under the License.
13 13
 
14
-// +build !windows
14
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
15 15
 
16 16
 package procfs
17 17
 
... ...
@@ -25,6 +25,7 @@ import (
25 25
 	"golang.org/x/sys/unix"
26 26
 )
27 27
 
28
+// ProcMapPermissions contains permission settings read from /proc/[pid]/maps
28 29
 type ProcMapPermissions struct {
29 30
 	// mapping has the [R]ead flag set
30 31
 	Read bool
... ...
@@ -40,7 +40,7 @@ func (p Proc) Namespaces() (Namespaces, error) {
40 40
 
41 41
 	names, err := d.Readdirnames(-1)
42 42
 	if err != nil {
43
-		return nil, fmt.Errorf("failed to read contents of ns dir: %v", err)
43
+		return nil, fmt.Errorf("failed to read contents of ns dir: %w", err)
44 44
 	}
45 45
 
46 46
 	ns := make(Namespaces, len(names))
... ...
@@ -52,13 +52,13 @@ func (p Proc) Namespaces() (Namespaces, error) {
52 52
 
53 53
 		fields := strings.SplitN(target, ":", 2)
54 54
 		if len(fields) != 2 {
55
-			return nil, fmt.Errorf("failed to parse namespace type and inode from '%v'", target)
55
+			return nil, fmt.Errorf("failed to parse namespace type and inode from %q", target)
56 56
 		}
57 57
 
58 58
 		typ := fields[0]
59 59
 		inode, err := strconv.ParseUint(strings.Trim(fields[1], "[]"), 10, 32)
60 60
 		if err != nil {
61
-			return nil, fmt.Errorf("failed to parse inode from '%v': %v", fields[1], err)
61
+			return nil, fmt.Errorf("failed to parse inode from %q: %w", fields[1], err)
62 62
 		}
63 63
 
64 64
 		ns[name] = Namespace{typ, uint32(inode)}
... ...
@@ -59,7 +59,7 @@ type PSIStats struct {
59 59
 func (fs FS) PSIStatsForResource(resource string) (PSIStats, error) {
60 60
 	data, err := util.ReadFileNoStat(fs.proc.Path(fmt.Sprintf("%s/%s", "pressure", resource)))
61 61
 	if err != nil {
62
-		return PSIStats{}, fmt.Errorf("psi_stats: unavailable for %s", resource)
62
+		return PSIStats{}, fmt.Errorf("psi_stats: unavailable for %q: %w", resource, err)
63 63
 	}
64 64
 
65 65
 	return parsePSIStats(resource, bytes.NewReader(data))
66 66
new file mode 100644
... ...
@@ -0,0 +1,165 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+// +build !windows
14
+
15
+package procfs
16
+
17
+import (
18
+	"bufio"
19
+	"errors"
20
+	"fmt"
21
+	"os"
22
+	"regexp"
23
+	"strconv"
24
+	"strings"
25
+
26
+	"github.com/prometheus/procfs/internal/util"
27
+)
28
+
29
+var (
30
+	// match the header line before each mapped zone in /proc/pid/smaps
31
+	procSMapsHeaderLine = regexp.MustCompile(`^[a-f0-9].*$`)
32
+)
33
+
34
+type ProcSMapsRollup struct {
35
+	// Amount of the mapping that is currently resident in RAM
36
+	Rss uint64
37
+	// Process's proportional share of this mapping
38
+	Pss uint64
39
+	// Size in bytes of clean shared pages
40
+	SharedClean uint64
41
+	// Size in bytes of dirty shared pages
42
+	SharedDirty uint64
43
+	// Size in bytes of clean private pages
44
+	PrivateClean uint64
45
+	// Size in bytes of dirty private pages
46
+	PrivateDirty uint64
47
+	// Amount of memory currently marked as referenced or accessed
48
+	Referenced uint64
49
+	// Amount of memory that does not belong to any file
50
+	Anonymous uint64
51
+	// Amount would-be-anonymous memory currently on swap
52
+	Swap uint64
53
+	// Process's proportional memory on swap
54
+	SwapPss uint64
55
+}
56
+
57
+// ProcSMapsRollup reads from /proc/[pid]/smaps_rollup to get summed memory information of the
58
+// process.
59
+//
60
+// If smaps_rollup does not exists (require kernel >= 4.15), the content of /proc/pid/smaps will
61
+// we read and summed.
62
+func (p Proc) ProcSMapsRollup() (ProcSMapsRollup, error) {
63
+	data, err := util.ReadFileNoStat(p.path("smaps_rollup"))
64
+	if err != nil && os.IsNotExist(err) {
65
+		return p.procSMapsRollupManual()
66
+	}
67
+	if err != nil {
68
+		return ProcSMapsRollup{}, err
69
+	}
70
+
71
+	lines := strings.Split(string(data), "\n")
72
+	smaps := ProcSMapsRollup{}
73
+
74
+	// skip first line which don't contains information we need
75
+	lines = lines[1:]
76
+	for _, line := range lines {
77
+		if line == "" {
78
+			continue
79
+		}
80
+
81
+		if err := smaps.parseLine(line); err != nil {
82
+			return ProcSMapsRollup{}, err
83
+		}
84
+	}
85
+
86
+	return smaps, nil
87
+}
88
+
89
+// Read /proc/pid/smaps and do the roll-up in Go code.
90
+func (p Proc) procSMapsRollupManual() (ProcSMapsRollup, error) {
91
+	file, err := os.Open(p.path("smaps"))
92
+	if err != nil {
93
+		return ProcSMapsRollup{}, err
94
+	}
95
+	defer file.Close()
96
+
97
+	smaps := ProcSMapsRollup{}
98
+	scan := bufio.NewScanner(file)
99
+
100
+	for scan.Scan() {
101
+		line := scan.Text()
102
+
103
+		if procSMapsHeaderLine.MatchString(line) {
104
+			continue
105
+		}
106
+
107
+		if err := smaps.parseLine(line); err != nil {
108
+			return ProcSMapsRollup{}, err
109
+		}
110
+	}
111
+
112
+	return smaps, nil
113
+}
114
+
115
+func (s *ProcSMapsRollup) parseLine(line string) error {
116
+	kv := strings.SplitN(line, ":", 2)
117
+	if len(kv) != 2 {
118
+		fmt.Println(line)
119
+		return errors.New("invalid net/dev line, missing colon")
120
+	}
121
+
122
+	k := kv[0]
123
+	if k == "VmFlags" {
124
+		return nil
125
+	}
126
+
127
+	v := strings.TrimSpace(kv[1])
128
+	v = strings.TrimRight(v, " kB")
129
+
130
+	vKBytes, err := strconv.ParseUint(v, 10, 64)
131
+	if err != nil {
132
+		return err
133
+	}
134
+	vBytes := vKBytes * 1024
135
+
136
+	s.addValue(k, v, vKBytes, vBytes)
137
+
138
+	return nil
139
+}
140
+
141
+func (s *ProcSMapsRollup) addValue(k string, vString string, vUint uint64, vUintBytes uint64) {
142
+	switch k {
143
+	case "Rss":
144
+		s.Rss += vUintBytes
145
+	case "Pss":
146
+		s.Pss += vUintBytes
147
+	case "Shared_Clean":
148
+		s.SharedClean += vUintBytes
149
+	case "Shared_Dirty":
150
+		s.SharedDirty += vUintBytes
151
+	case "Private_Clean":
152
+		s.PrivateClean += vUintBytes
153
+	case "Private_Dirty":
154
+		s.PrivateDirty += vUintBytes
155
+	case "Referenced":
156
+		s.Referenced += vUintBytes
157
+	case "Anonymous":
158
+		s.Anonymous += vUintBytes
159
+	case "Swap":
160
+		s.Swap += vUintBytes
161
+	case "SwapPss":
162
+		s.SwapPss += vUintBytes
163
+	}
164
+}
... ...
@@ -100,6 +100,15 @@ type ProcStat struct {
100 100
 	VSize uint
101 101
 	// Resident set size in pages.
102 102
 	RSS int
103
+	// Soft limit in bytes on the rss of the process.
104
+	RSSLimit uint64
105
+	// Real-time scheduling priority, a number in the range 1 to 99 for processes
106
+	// scheduled under a real-time policy, or 0, for non-real-time processes.
107
+	RTPriority uint
108
+	// Scheduling policy.
109
+	Policy uint
110
+	// Aggregated block I/O delays, measured in clock ticks (centiseconds).
111
+	DelayAcctBlkIOTicks uint64
103 112
 
104 113
 	proc fs.FS
105 114
 }
... ...
@@ -119,7 +128,8 @@ func (p Proc) Stat() (ProcStat, error) {
119 119
 	}
120 120
 
121 121
 	var (
122
-		ignore int
122
+		ignoreInt64  int64
123
+		ignoreUint64 uint64
123 124
 
124 125
 		s = ProcStat{PID: p.PID, proc: p.fs}
125 126
 		l = bytes.Index(data, []byte("("))
... ...
@@ -127,10 +137,7 @@ func (p Proc) Stat() (ProcStat, error) {
127 127
 	)
128 128
 
129 129
 	if l < 0 || r < 0 {
130
-		return ProcStat{}, fmt.Errorf(
131
-			"unexpected format, couldn't extract comm: %s",
132
-			data,
133
-		)
130
+		return ProcStat{}, fmt.Errorf("unexpected format, couldn't extract comm %q", data)
134 131
 	}
135 132
 
136 133
 	s.Comm = string(data[l+1 : r])
... ...
@@ -154,10 +161,28 @@ func (p Proc) Stat() (ProcStat, error) {
154 154
 		&s.Priority,
155 155
 		&s.Nice,
156 156
 		&s.NumThreads,
157
-		&ignore,
157
+		&ignoreInt64,
158 158
 		&s.Starttime,
159 159
 		&s.VSize,
160 160
 		&s.RSS,
161
+		&s.RSSLimit,
162
+		&ignoreUint64,
163
+		&ignoreUint64,
164
+		&ignoreUint64,
165
+		&ignoreUint64,
166
+		&ignoreUint64,
167
+		&ignoreUint64,
168
+		&ignoreUint64,
169
+		&ignoreUint64,
170
+		&ignoreUint64,
171
+		&ignoreUint64,
172
+		&ignoreUint64,
173
+		&ignoreUint64,
174
+		&ignoreInt64,
175
+		&ignoreInt64,
176
+		&s.RTPriority,
177
+		&s.Policy,
178
+		&s.DelayAcctBlkIOTicks,
161 179
 	)
162 180
 	if err != nil {
163 181
 		return ProcStat{}, err
... ...
@@ -72,8 +72,10 @@ type ProcStatus struct {
72 72
 	// Number of involuntary context switches.
73 73
 	NonVoluntaryCtxtSwitches uint64
74 74
 
75
-	// UIDs of the process (Real, effective, saved set, and filesystem UIDs (GIDs))
75
+	// UIDs of the process (Real, effective, saved set, and filesystem UIDs)
76 76
 	UIDs [4]string
77
+	// GIDs of the process (Real, effective, saved set, and filesystem GIDs)
78
+	GIDs [4]string
77 79
 }
78 80
 
79 81
 // NewStatus returns the current status information of the process.
... ...
@@ -119,6 +121,8 @@ func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintByt
119 119
 		s.Name = vString
120 120
 	case "Uid":
121 121
 		copy(s.UIDs[:], strings.Split(vString, "\t"))
122
+	case "Gid":
123
+		copy(s.GIDs[:], strings.Split(vString, "\t"))
122 124
 	case "VmPeak":
123 125
 		s.VmPeak = vUintBytes
124 126
 	case "VmSize":
... ...
@@ -95,24 +95,27 @@ func (fs FS) Schedstat() (*Schedstat, error) {
95 95
 	return stats, nil
96 96
 }
97 97
 
98
-func parseProcSchedstat(contents string) (stats ProcSchedstat, err error) {
98
+func parseProcSchedstat(contents string) (ProcSchedstat, error) {
99
+	var (
100
+		stats ProcSchedstat
101
+		err   error
102
+	)
99 103
 	match := procLineRE.FindStringSubmatch(contents)
100 104
 
101 105
 	if match != nil {
102 106
 		stats.RunningNanoseconds, err = strconv.ParseUint(match[1], 10, 64)
103 107
 		if err != nil {
104
-			return
108
+			return stats, err
105 109
 		}
106 110
 
107 111
 		stats.WaitingNanoseconds, err = strconv.ParseUint(match[2], 10, 64)
108 112
 		if err != nil {
109
-			return
113
+			return stats, err
110 114
 		}
111 115
 
112 116
 		stats.RunTimeslices, err = strconv.ParseUint(match[3], 10, 64)
113
-		return
117
+		return stats, err
114 118
 	}
115 119
 
116
-	err = errors.New("could not parse schedstat")
117
-	return
120
+	return stats, errors.New("could not parse schedstat")
118 121
 }
119 122
new file mode 100644
... ...
@@ -0,0 +1,151 @@
0
+// Copyright 2020 The Prometheus Authors
1
+// Licensed under the Apache License, Version 2.0 (the "License");
2
+// you may not use this file except in compliance with the License.
3
+// You may obtain a copy of the License at
4
+//
5
+// http://www.apache.org/licenses/LICENSE-2.0
6
+//
7
+// Unless required by applicable law or agreed to in writing, software
8
+// distributed under the License is distributed on an "AS IS" BASIS,
9
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+// See the License for the specific language governing permissions and
11
+// limitations under the License.
12
+
13
+package procfs
14
+
15
+import (
16
+	"bufio"
17
+	"bytes"
18
+	"fmt"
19
+	"regexp"
20
+	"strconv"
21
+	"strings"
22
+
23
+	"github.com/prometheus/procfs/internal/util"
24
+)
25
+
26
+var (
27
+	slabSpace  = regexp.MustCompile(`\s+`)
28
+	slabVer    = regexp.MustCompile(`slabinfo -`)
29
+	slabHeader = regexp.MustCompile(`# name`)
30
+)
31
+
32
+// Slab represents a slab pool in the kernel.
33
+type Slab struct {
34
+	Name         string
35
+	ObjActive    int64
36
+	ObjNum       int64
37
+	ObjSize      int64
38
+	ObjPerSlab   int64
39
+	PagesPerSlab int64
40
+	// tunables
41
+	Limit        int64
42
+	Batch        int64
43
+	SharedFactor int64
44
+	SlabActive   int64
45
+	SlabNum      int64
46
+	SharedAvail  int64
47
+}
48
+
49
+// SlabInfo represents info for all slabs.
50
+type SlabInfo struct {
51
+	Slabs []*Slab
52
+}
53
+
54
+func shouldParseSlab(line string) bool {
55
+	if slabVer.MatchString(line) {
56
+		return false
57
+	}
58
+	if slabHeader.MatchString(line) {
59
+		return false
60
+	}
61
+	return true
62
+}
63
+
64
+// parseV21SlabEntry is used to parse a line from /proc/slabinfo version 2.1.
65
+func parseV21SlabEntry(line string) (*Slab, error) {
66
+	// First cleanup whitespace.
67
+	l := slabSpace.ReplaceAllString(line, " ")
68
+	s := strings.Split(l, " ")
69
+	if len(s) != 16 {
70
+		return nil, fmt.Errorf("unable to parse: %q", line)
71
+	}
72
+	var err error
73
+	i := &Slab{Name: s[0]}
74
+	i.ObjActive, err = strconv.ParseInt(s[1], 10, 64)
75
+	if err != nil {
76
+		return nil, err
77
+	}
78
+	i.ObjNum, err = strconv.ParseInt(s[2], 10, 64)
79
+	if err != nil {
80
+		return nil, err
81
+	}
82
+	i.ObjSize, err = strconv.ParseInt(s[3], 10, 64)
83
+	if err != nil {
84
+		return nil, err
85
+	}
86
+	i.ObjPerSlab, err = strconv.ParseInt(s[4], 10, 64)
87
+	if err != nil {
88
+		return nil, err
89
+	}
90
+	i.PagesPerSlab, err = strconv.ParseInt(s[5], 10, 64)
91
+	if err != nil {
92
+		return nil, err
93
+	}
94
+	i.Limit, err = strconv.ParseInt(s[8], 10, 64)
95
+	if err != nil {
96
+		return nil, err
97
+	}
98
+	i.Batch, err = strconv.ParseInt(s[9], 10, 64)
99
+	if err != nil {
100
+		return nil, err
101
+	}
102
+	i.SharedFactor, err = strconv.ParseInt(s[10], 10, 64)
103
+	if err != nil {
104
+		return nil, err
105
+	}
106
+	i.SlabActive, err = strconv.ParseInt(s[13], 10, 64)
107
+	if err != nil {
108
+		return nil, err
109
+	}
110
+	i.SlabNum, err = strconv.ParseInt(s[14], 10, 64)
111
+	if err != nil {
112
+		return nil, err
113
+	}
114
+	i.SharedAvail, err = strconv.ParseInt(s[15], 10, 64)
115
+	if err != nil {
116
+		return nil, err
117
+	}
118
+	return i, nil
119
+}
120
+
121
+// parseSlabInfo21 is used to parse a slabinfo 2.1 file.
122
+func parseSlabInfo21(r *bytes.Reader) (SlabInfo, error) {
123
+	scanner := bufio.NewScanner(r)
124
+	s := SlabInfo{Slabs: []*Slab{}}
125
+	for scanner.Scan() {
126
+		line := scanner.Text()
127
+		if !shouldParseSlab(line) {
128
+			continue
129
+		}
130
+		slab, err := parseV21SlabEntry(line)
131
+		if err != nil {
132
+			return s, err
133
+		}
134
+		s.Slabs = append(s.Slabs, slab)
135
+	}
136
+	return s, nil
137
+}
138
+
139
+// SlabInfo reads data from /proc/slabinfo
140
+func (fs FS) SlabInfo() (SlabInfo, error) {
141
+	// TODO: Consider passing options to allow for parsing different
142
+	// slabinfo versions. However, slabinfo 2.1 has been stable since
143
+	// kernel 2.6.10 and later.
144
+	data, err := util.ReadFileNoStat(fs.proc.Path("slabinfo"))
145
+	if err != nil {
146
+		return SlabInfo{}, err
147
+	}
148
+
149
+	return parseSlabInfo21(bytes.NewReader(data))
150
+}
... ...
@@ -93,10 +93,10 @@ func parseCPUStat(line string) (CPUStat, int64, error) {
93 93
 		&cpuStat.Guest, &cpuStat.GuestNice)
94 94
 
95 95
 	if err != nil && err != io.EOF {
96
-		return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): %s", line, err)
96
+		return CPUStat{}, -1, fmt.Errorf("couldn't parse %q (cpu): %w", line, err)
97 97
 	}
98 98
 	if count == 0 {
99
-		return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): 0 elements parsed", line)
99
+		return CPUStat{}, -1, fmt.Errorf("couldn't parse %q (cpu): 0 elements parsed", line)
100 100
 	}
101 101
 
102 102
 	cpuStat.User /= userHZ
... ...
@@ -116,7 +116,7 @@ func parseCPUStat(line string) (CPUStat, int64, error) {
116 116
 
117 117
 	cpuID, err := strconv.ParseInt(cpu[3:], 10, 64)
118 118
 	if err != nil {
119
-		return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu/cpuid): %s", line, err)
119
+		return CPUStat{}, -1, fmt.Errorf("couldn't parse %q (cpu/cpuid): %w", line, err)
120 120
 	}
121 121
 
122 122
 	return cpuStat, cpuID, nil
... ...
@@ -136,7 +136,7 @@ func parseSoftIRQStat(line string) (SoftIRQStat, uint64, error) {
136 136
 		&softIRQStat.Hrtimer, &softIRQStat.Rcu)
137 137
 
138 138
 	if err != nil {
139
-		return SoftIRQStat{}, 0, fmt.Errorf("couldn't parse %s (softirq): %s", line, err)
139
+		return SoftIRQStat{}, 0, fmt.Errorf("couldn't parse %q (softirq): %w", line, err)
140 140
 	}
141 141
 
142 142
 	return softIRQStat, total, nil
... ...
@@ -184,34 +184,34 @@ func (fs FS) Stat() (Stat, error) {
184 184
 		switch {
185 185
 		case parts[0] == "btime":
186 186
 			if stat.BootTime, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
187
-				return Stat{}, fmt.Errorf("couldn't parse %s (btime): %s", parts[1], err)
187
+				return Stat{}, fmt.Errorf("couldn't parse %q (btime): %w", parts[1], err)
188 188
 			}
189 189
 		case parts[0] == "intr":
190 190
 			if stat.IRQTotal, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
191
-				return Stat{}, fmt.Errorf("couldn't parse %s (intr): %s", parts[1], err)
191
+				return Stat{}, fmt.Errorf("couldn't parse %q (intr): %w", parts[1], err)
192 192
 			}
193 193
 			numberedIRQs := parts[2:]
194 194
 			stat.IRQ = make([]uint64, len(numberedIRQs))
195 195
 			for i, count := range numberedIRQs {
196 196
 				if stat.IRQ[i], err = strconv.ParseUint(count, 10, 64); err != nil {
197
-					return Stat{}, fmt.Errorf("couldn't parse %s (intr%d): %s", count, i, err)
197
+					return Stat{}, fmt.Errorf("couldn't parse %q (intr%d): %w", count, i, err)
198 198
 				}
199 199
 			}
200 200
 		case parts[0] == "ctxt":
201 201
 			if stat.ContextSwitches, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
202
-				return Stat{}, fmt.Errorf("couldn't parse %s (ctxt): %s", parts[1], err)
202
+				return Stat{}, fmt.Errorf("couldn't parse %q (ctxt): %w", parts[1], err)
203 203
 			}
204 204
 		case parts[0] == "processes":
205 205
 			if stat.ProcessCreated, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
206
-				return Stat{}, fmt.Errorf("couldn't parse %s (processes): %s", parts[1], err)
206
+				return Stat{}, fmt.Errorf("couldn't parse %q (processes): %w", parts[1], err)
207 207
 			}
208 208
 		case parts[0] == "procs_running":
209 209
 			if stat.ProcessesRunning, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
210
-				return Stat{}, fmt.Errorf("couldn't parse %s (procs_running): %s", parts[1], err)
210
+				return Stat{}, fmt.Errorf("couldn't parse %q (procs_running): %w", parts[1], err)
211 211
 			}
212 212
 		case parts[0] == "procs_blocked":
213 213
 			if stat.ProcessesBlocked, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
214
-				return Stat{}, fmt.Errorf("couldn't parse %s (procs_blocked): %s", parts[1], err)
214
+				return Stat{}, fmt.Errorf("couldn't parse %q (procs_blocked): %w", parts[1], err)
215 215
 			}
216 216
 		case parts[0] == "softirq":
217 217
 			softIRQStats, total, err := parseSoftIRQStat(line)
... ...
@@ -237,7 +237,7 @@ func (fs FS) Stat() (Stat, error) {
237 237
 	}
238 238
 
239 239
 	if err := scanner.Err(); err != nil {
240
-		return Stat{}, fmt.Errorf("couldn't parse %s: %s", fileName, err)
240
+		return Stat{}, fmt.Errorf("couldn't parse %q: %w", fileName, err)
241 241
 	}
242 242
 
243 243
 	return stat, nil
... ...
@@ -112,8 +112,7 @@ func (fs FS) NewXfrmStat() (XfrmStat, error) {
112 112
 		fields := strings.Fields(s.Text())
113 113
 
114 114
 		if len(fields) != 2 {
115
-			return XfrmStat{}, fmt.Errorf(
116
-				"couldn't parse %s line %s", file.Name(), s.Text())
115
+			return XfrmStat{}, fmt.Errorf("couldn't parse %q line %q", file.Name(), s.Text())
117 116
 		}
118 117
 
119 118
 		name := fields[0]
... ...
@@ -74,11 +74,11 @@ var nodeZoneRE = regexp.MustCompile(`(\d+), zone\s+(\w+)`)
74 74
 func (fs FS) Zoneinfo() ([]Zoneinfo, error) {
75 75
 	data, err := ioutil.ReadFile(fs.proc.Path("zoneinfo"))
76 76
 	if err != nil {
77
-		return nil, fmt.Errorf("error reading zoneinfo %s: %s", fs.proc.Path("zoneinfo"), err)
77
+		return nil, fmt.Errorf("error reading zoneinfo %q: %w", fs.proc.Path("zoneinfo"), err)
78 78
 	}
79 79
 	zoneinfo, err := parseZoneinfo(data)
80 80
 	if err != nil {
81
-		return nil, fmt.Errorf("error parsing zoneinfo %s: %s", fs.proc.Path("zoneinfo"), err)
81
+		return nil, fmt.Errorf("error parsing zoneinfo %q: %w", fs.proc.Path("zoneinfo"), err)
82 82
 	}
83 83
 	return zoneinfo, nil
84 84
 }
... ...
@@ -99,7 +99,6 @@ func parseZoneinfo(zoneinfoData []byte) ([]Zoneinfo, error) {
99 99
 				continue
100 100
 			}
101 101
 			if strings.HasPrefix(strings.TrimSpace(line), "per-node stats") {
102
-				zoneinfoElement.Zone = ""
103 102
 				continue
104 103
 			}
105 104
 			parts := strings.Fields(strings.TrimSpace(line))
... ...
@@ -709,8 +709,8 @@ github.com/philhofer/fwd
709 709
 # github.com/pkg/errors v0.9.1
710 710
 ## explicit
711 711
 github.com/pkg/errors
712
-# github.com/prometheus/client_golang v1.12.1 => github.com/prometheus/client_golang v1.6.0
713
-## explicit; go 1.11
712
+# github.com/prometheus/client_golang v1.12.1
713
+## explicit; go 1.13
714 714
 github.com/prometheus/client_golang/prometheus
715 715
 github.com/prometheus/client_golang/prometheus/internal
716 716
 github.com/prometheus/client_golang/prometheus/promhttp
... ...
@@ -722,8 +722,8 @@ github.com/prometheus/client_model/go
722 722
 github.com/prometheus/common/expfmt
723 723
 github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg
724 724
 github.com/prometheus/common/model
725
-# github.com/prometheus/procfs v0.7.3 => github.com/prometheus/procfs v0.0.11
726
-## explicit; go 1.12
725
+# github.com/prometheus/procfs v0.7.3
726
+## explicit; go 1.13
727 727
 github.com/prometheus/procfs
728 728
 github.com/prometheus/procfs/internal/fs
729 729
 github.com/prometheus/procfs/internal/util
... ...
@@ -1120,7 +1120,5 @@ gotest.tools/v3/skip
1120 1120
 # github.com/armon/go-radix => github.com/armon/go-radix v0.0.0-20150105235045-e39d623f12e8
1121 1121
 # github.com/hashicorp/go-msgpack => github.com/hashicorp/go-msgpack v0.0.0-20140221154404-71c2886f5a67
1122 1122
 # github.com/hashicorp/serf => github.com/hashicorp/serf v0.7.1-0.20160317193612-598c54895cc5
1123
-# github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.6.0
1124
-# github.com/prometheus/procfs => github.com/prometheus/procfs v0.0.11
1125 1123
 # github.com/rexray/gocsi => github.com/dperny/gocsi v1.2.3-pre
1126 1124
 # github.com/google/certificate-transparency-go => github.com/google/certificate-transparency-go v1.0.20