Full Code of kubernetes/klog for AI

main dbd6b2bc8a30 cached
107 files
442.4 KB
128.7k tokens
705 symbols
1 requests
Download .txt
Showing preview only (472K chars total). Download the full file or copy to clipboard to get everything.
Repository: kubernetes/klog
Branch: main
Commit: dbd6b2bc8a30
Files: 107
Total size: 442.4 KB

Directory structure:
gitextract_iyzg6fyz/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── lint.yml
│       └── test.yml
├── .gitignore
├── .golangci.yaml
├── CONTRIBUTING.md
├── LICENSE
├── OWNERS
├── README.md
├── RELEASE.md
├── SECURITY.md
├── SECURITY_CONTACTS
├── code-of-conduct.md
├── contextual.go
├── contextual_slog.go
├── contextual_slog_example_test.go
├── contextual_test.go
├── examples/
│   ├── benchmarks/
│   │   └── benchmarks_test.go
│   ├── coexist_glog/
│   │   └── coexist_glog.go
│   ├── coexist_klog_v1_and_v2/
│   │   ├── coexist_klog_v1_and_v2.go
│   │   └── go.mod
│   ├── flushing/
│   │   ├── .gitignore
│   │   └── flushing_test.go
│   ├── go.mod
│   ├── go.sum
│   ├── go_vet/
│   │   ├── go_vet_test.go
│   │   └── testdata/
│   │       └── calls.go
│   ├── klogr/
│   │   └── main.go
│   ├── log_file/
│   │   └── usage_log_file.go
│   ├── output_test/
│   │   └── output_test.go
│   ├── set_output/
│   │   └── usage_set_output.go
│   ├── stderr_threshold_fix/
│   │   └── main.go
│   ├── structured_logging/
│   │   └── structured_logging.go
│   └── util/
│       └── require/
│           └── require.go
├── exit.go
├── exit_test.go
├── format.go
├── format_test.go
├── go.mod
├── go.sum
├── hack/
│   └── verify-apidiff.sh
├── imports.go
├── integration_tests/
│   ├── internal/
│   │   └── main.go
│   └── klog_test.go
├── internal/
│   ├── buffer/
│   │   └── buffer.go
│   ├── clock/
│   │   ├── README.md
│   │   ├── clock.go
│   │   └── testing/
│   │       ├── fake_clock.go
│   │       └── simple_interval_clock.go
│   ├── dbg/
│   │   └── dbg.go
│   ├── serialize/
│   │   ├── keyvalues.go
│   │   ├── keyvalues_no_slog.go
│   │   ├── keyvalues_slog.go
│   │   └── keyvalues_test.go
│   ├── severity/
│   │   └── severity.go
│   ├── sloghandler/
│   │   └── sloghandler_slog.go
│   ├── test/
│   │   ├── mock.go
│   │   └── require/
│   │       └── require.go
│   └── verbosity/
│       ├── helper_test.go
│       ├── verbosity.go
│       └── verbosity_test.go
├── k8s_references.go
├── k8s_references_slog.go
├── klog.go
├── klog_file.go
├── klog_file_others.go
├── klog_file_windows.go
├── klog_test.go
├── klog_wrappers_test.go
├── klogr/
│   ├── README.md
│   ├── calldepth-test/
│   │   ├── call_depth_helper_test.go
│   │   └── call_depth_main_test.go
│   ├── klogr.go
│   ├── klogr_test.go
│   └── output_test.go
├── klogr.go
├── klogr_helper_test.go
├── klogr_slog.go
├── klogr_slog_test.go
├── klogr_test.go
├── ktesting/
│   ├── contextual_test.go
│   ├── example/
│   │   └── example_test.go
│   ├── example_test.go
│   ├── helper_test.go
│   ├── init/
│   │   └── init.go
│   ├── main_test.go
│   ├── options.go
│   ├── setup.go
│   ├── testinglogger.go
│   └── testinglogger_test.go
├── output_test.go
├── safeptr.go
├── safeptr_test.go
├── stderr_threshold_test.go
├── test/
│   ├── output.go
│   ├── output_helper.go
│   └── zapr.go
└── textlogger/
    ├── example_test.go
    ├── options.go
    ├── output_test.go
    ├── textlogger.go
    ├── textlogger_slog.go
    ├── textlogger_slog_test.go
    └── textlogger_test.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Tell us about a problem you are experiencing

---

/kind bug

**What steps did you take and what happened:**
[A clear and concise description of what the bug is.]


**What did you expect to happen:**


**Anything else you would like to add:**
[Miscellaneous information that will assist in solving the issue.]


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature enhancement request
about: Suggest an idea for this project

---

/kind feature

**Describe the solution you'd like**
[A clear and concise description of what you want to happen.]


**Anything else you would like to add:**
[Miscellaneous information that will assist in solving the issue.]


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--  Thanks for sending a pull request!  Here are some tips for you:
1. If this is your first time, read our contributor guidelines https://git.k8s.io/community/contributors/guide/pull-requests.md#the-pull-request-submit-process and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
3. Follow the instructions for writing a release note: https://git.k8s.io/community/contributors/guide/release-notes.md
4. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
5. If this PR changes image versions, please title this PR "Bump <image name> from x.x.x to y.y.y."
-->

**What this PR does / why we need it**:

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes #

**Special notes for your reviewer**:

_Please confirm that if this PR changes any image versions, then that's the sole change this PR makes._

**Release note**:
<!--  Write your release note:
1. Enter your extended release note in the below block. If the PR requires additional action from users switching to the new release, include the string "action required".
2. If no release note is required, just write "NONE".
-->
```release-note

```

================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: gomod
    directories:
      - "**/*"
    schedule:
      interval: daily

  - package-ecosystem: github-actions
    directory: /
    schedule:
      interval: daily


================================================
FILE: .github/workflows/lint.yml
================================================
name: Run lint

on: [ push, pull_request ]

permissions:
  contents: read

jobs:
  lint:
    strategy:
      matrix:
        path:
          - .
          - examples
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Lint
        uses: golangci/golangci-lint-action@v6
        with:
          # version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
          version: latest
          working-directory: ${{ matrix.path }}


================================================
FILE: .github/workflows/test.yml
================================================
name: Test
on: [push, pull_request]
jobs:
  test:
    strategy:
      matrix:
        go-version: ["1.21", "1.22", "1.23", "1.24", "1.25"]
        platform: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.platform }}
    steps:
    - name: Install Go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ matrix.go-version }}
    - name: Checkout code
      uses: actions/checkout@v4
    - name: Test klog
      run: |
        go get -t -v ./...
        go test -v -race ./...
    - name: Test examples
      run: cd examples && go test -v -race ./...
  apidiff:
    runs-on: ubuntu-latest
    if: github.base_ref
    steps:
      - name: Install Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.23
      - name: Add GOBIN to PATH
        run: echo "PATH=$(go env GOPATH)/bin:$PATH" >>$GITHUB_ENV
      - name: Install dependencies
        run: go install golang.org/x/exp/cmd/apidiff@latest
      - name: Checkout old code
        uses: actions/checkout@v4
        with:
          ref: ${{ github.base_ref }}
          path: "old"
      - name: Checkout new code
        uses: actions/checkout@v4
        with:
          path: "new"
      - name: APIDiff
        run: ./hack/verify-apidiff.sh -d ../old
        working-directory: "new"


================================================
FILE: .gitignore
================================================
# OSX leaves these everywhere on SMB shares
._*

# OSX trash
.DS_Store

# Eclipse files
.classpath
.project
.settings/**

# Files generated by JetBrains IDEs, e.g. IntelliJ IDEA
.idea/
*.iml

# Vscode files
.vscode


================================================
FILE: .golangci.yaml
================================================
linters:
  disable-all: true
  enable: # sorted alphabetical
    - gofmt
    - misspell
    - revive


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing Guidelines

Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://github.com/kubernetes/community)! The Kubernetes community abides by the CNCF [code of conduct](code-of-conduct.md). Here is an excerpt:

_As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._

## Getting Started

We have full documentation on how to get started contributing here:

- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests
- [Kubernetes Contributor Guide](http://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](http://git.k8s.io/community/contributors/guide#contributing)
- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet) - Common resources for existing developers

## Mentorship

- [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers!

## Contact Information

- [Slack](https://kubernetes.slack.com/messages/sig-architecture)
- [Mailing List](https://groups.google.com/forum/#!forum/kubernetes-sig-architecture)


================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.

"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.

"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.

"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.

"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.

"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).

"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.

"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."

"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.

2. Grant of Copyright License.

Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.

3. Grant of Patent License.

Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.

4. Redistribution.

You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:

You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.

5. Submission of Contributions.

Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.

6. Trademarks.

This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.

7. Disclaimer of Warranty.

Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.

8. Limitation of Liability.

In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability.

While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work

To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "[]" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

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

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: OWNERS
================================================
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
  - harshanarayana
  - mengjiao-liu
  - pohly
approvers:
  - dims
  - pohly
  - thockin
emeritus_approvers:
  - brancz
  - justinsb
  - lavalamp
  - piosz
  - serathius
  - tallclair


================================================
FILE: README.md
================================================
klog
====

klog is a permanent fork of https://github.com/golang/glog.

## Why was klog created?

The decision to create klog was one that wasn't made lightly, but it was necessary due to some
drawbacks that are present in [glog](https://github.com/golang/glog). Ultimately, the fork was created due to glog not being under active development; this can be seen in the glog README:

> The code in this repo [...] is not itself under development

This makes us unable to solve many use cases without a fork. The factors that contributed to needing feature development are listed below:

 * `glog` [presents a lot "gotchas"](https://github.com/kubernetes/kubernetes/issues/61006) and introduces challenges in containerized environments, all of which aren't well documented.
 * `glog` doesn't provide an easy way to test logs, which detracts from the stability of software using it
 * A long term goal is to implement a logging interface that allows us to add context, change output format, etc.
 
Historical context is available here:

 * https://github.com/kubernetes/kubernetes/issues/61006
 * https://github.com/kubernetes/kubernetes/issues/70264
 * https://groups.google.com/forum/#!msg/kubernetes-sig-architecture/wCWiWf3Juzs/hXRVBH90CgAJ
 * https://groups.google.com/forum/#!msg/kubernetes-dev/7vnijOMhLS0/1oRiNtigBgAJ

## Release versioning

Semantic versioning is used in this repository. It contains several Go modules
with different levels of stability:
- `k8s.io/klog/v2` - stable API, `vX.Y.Z` tags
- `examples` - no stable API, no tags, no intention to ever stabilize

Exempt from the API stability guarantee are items (packages, functions, etc.)
which are marked explicitly as `EXPERIMENTAL` in their docs comment. Those
may still change in incompatible ways or get removed entirely. This can only
be used for code that is used in tests to avoid situations where non-test
code from two different Kubernetes dependencies depends on incompatible
releases of klog because an experimental API was changed.

----

How to use klog
===============
- Replace imports for `"github.com/golang/glog"` with `"k8s.io/klog/v2"`
- Use `klog.InitFlags(nil)` explicitly for initializing global flags as we no longer use `init()` method to register the flags
- You can now use `log_file` instead of `log_dir` for logging to a single file (See `examples/log_file/usage_log_file.go`)
- If you want to redirect everything logged using klog somewhere else (say syslog!), you can use `klog.SetOutput()` method and supply a `io.Writer`. (See `examples/set_output/usage_set_output.go`)
- For more logging conventions (See [Logging Conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md))
- See our documentation on [pkg.go.dev/k8s.io](https://pkg.go.dev/k8s.io/klog).

### Coexisting with klog/v2

See [this example](examples/coexist_klog_v1_and_v2/) to see how to coexist with both klog/v1 and klog/v2.

### Coexisting with glog
This package can be used side by side with glog. [This example](examples/coexist_glog/coexist_glog.go) shows how to initialize and synchronize flags from the global `flag.CommandLine` FlagSet. In addition, the example makes use of stderr as combined output by setting `alsologtostderr` (or `logtostderr`) to `true`.

## Community, discussion, contribution, and support

Learn how to engage with the Kubernetes community on the [community page](http://kubernetes.io/community/).

You can reach the maintainers of this project at:

- [Slack](https://kubernetes.slack.com/messages/klog)
- [Mailing List](https://groups.google.com/forum/#!forum/kubernetes-sig-architecture)

### Code of conduct

Participation in the Kubernetes community is governed by the [Kubernetes Code of Conduct](code-of-conduct.md).

----

glog
====

Leveled execution logs for Go.

This is an efficient pure Go implementation of leveled logs in the
manner of the open source C++ package
	https://github.com/google/glog

By binding methods to booleans it is possible to use the log package
without paying the expense of evaluating the arguments to the log.
Through the -vmodule flag, the package also provides fine-grained
control over logging at the file level.

The comment from glog.go introduces the ideas:

	Package glog implements logging analogous to the Google-internal
	C++ INFO/ERROR/V setup.  It provides functions Info, Warning,
	Error, Fatal, plus formatting variants such as Infof. It
	also provides V-style logging controlled by the -v and
	-vmodule=file=2 flags.

	Basic examples:

		glog.Info("Prepare to repel boarders")

		glog.Fatalf("Initialization failed: %s", err)

	See the documentation of the V function for an explanation
	of these examples:

		if glog.V(2) {
			glog.Info("Starting transaction...")
		}

		glog.V(2).Infoln("Processed", nItems, "elements")


The repository contains an open source version of the log package
used inside Google. The master copy of the source lives inside
Google, not here. The code in this repo is for export only and is not itself
under development. Feature requests will be ignored.

Send bug reports to golang-nuts@googlegroups.com.


================================================
FILE: RELEASE.md
================================================
# Release Process

The `klog` is released on an as-needed basis. The process is as follows:

1. An issue is proposing a new release with a changelog since the last release
1. All [OWNERS](OWNERS) must LGTM this release
1. An OWNER runs `git tag -s $VERSION` and inserts the changelog and pushes the tag with `git push $VERSION`
1. The release issue is closed
1. An announcement email is sent to `kubernetes-dev@googlegroups.com` with the subject `[ANNOUNCE] kubernetes-template-project $VERSION is released`


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Security Announcements

Join the [kubernetes-security-announce] group for security and vulnerability announcements.

You can also subscribe to an RSS feed of the above using [this link][kubernetes-security-announce-rss].

## Reporting a Vulnerability

Instructions for reporting a vulnerability can be found on the
[Kubernetes Security and Disclosure Information] page.

## Supported Versions

Information about supported Kubernetes versions can be found on the
[Kubernetes version and version skew support policy] page on the Kubernetes website.

[kubernetes-security-announce]: https://groups.google.com/forum/#!forum/kubernetes-security-announce
[kubernetes-security-announce-rss]: https://groups.google.com/forum/feed/kubernetes-security-announce/msgs/rss_v2_0.xml?num=50
[Kubernetes version and version skew support policy]: https://kubernetes.io/docs/setup/release/version-skew-policy/#supported-versions
[Kubernetes Security and Disclosure Information]: https://kubernetes.io/docs/reference/issues-security/security/#report-a-vulnerability


================================================
FILE: SECURITY_CONTACTS
================================================
# Defined below are the security contacts for this repo.
#
# They are the contact point for the Product Security Committee to reach out
# to for triaging and handling of incoming issues.
#
# The below names agree to abide by the
# [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy)
# and will be removed and replaced if they violate that agreement.
#
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
# INSTRUCTIONS AT https://kubernetes.io/security/

dims
thockin
justinsb
tallclair
piosz
brancz
DirectXMan12
lavalamp


================================================
FILE: code-of-conduct.md
================================================
# Kubernetes Community Code of Conduct

Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)


================================================
FILE: contextual.go
================================================
/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package klog

import (
	"context"

	"github.com/go-logr/logr"
)

// This file provides the implementation of
// https://github.com/kubernetes/enhancements/tree/master/keps/sig-instrumentation/1602-structured-logging
//
// SetLogger and ClearLogger were originally added to klog.go and got moved
// here. Contextual logging adds a way to retrieve a Logger for direct logging
// without the logging calls in klog.go.
//
// The global variables are expected to be modified only during sequential
// parts of a program (init, serial tests) and therefore are not protected by
// mutex locking.

var (
	// klogLogger is used as fallback for logging through the normal klog code
	// when no Logger is set.
	klogLogger logr.Logger = logr.New(&klogger{})
)

// SetLogger sets a Logger implementation that will be used as backing
// implementation of the traditional klog log calls. klog will do its own
// verbosity checks before calling logger.V().Info. logger.Error is always
// called, regardless of the klog verbosity settings.
//
// If set, all log lines will be suppressed from the regular output, and
// redirected to the logr implementation.
// Use as:
//
//	...
//	klog.SetLogger(zapr.NewLogger(zapLog))
//
// To remove a backing logr implemention, use ClearLogger. Setting an
// empty logger with SetLogger(logr.Logger{}) does not work.
//
// Modifying the logger is not thread-safe and should be done while no other
// goroutines invoke log calls, usually during program initialization.
func SetLogger(logger logr.Logger) {
	SetLoggerWithOptions(logger)
}

// SetLoggerWithOptions is a more flexible version of SetLogger. Without
// additional options, it behaves exactly like SetLogger. By passing
// ContextualLogger(true) as option, it can be used to set a logger that then
// will also get called directly by applications which retrieve it via
// FromContext, Background, or TODO.
//
// Supporting direct calls is recommended because it avoids the overhead of
// routing log entries through klogr into klog and then into the actual Logger
// backend.
func SetLoggerWithOptions(logger logr.Logger, opts ...LoggerOption) {
	logging.loggerOptions = loggerOptions{}
	for _, opt := range opts {
		opt(&logging.loggerOptions)
	}
	logging.logger = &logWriter{
		Logger:          logger,
		writeKlogBuffer: logging.loggerOptions.writeKlogBuffer,
	}
}

// ContextualLogger determines whether the logger passed to
// SetLoggerWithOptions may also get called directly. Such a logger cannot rely
// on verbosity checking in klog.
func ContextualLogger(enabled bool) LoggerOption {
	return func(o *loggerOptions) {
		o.contextualLogger = enabled
	}
}

// FlushLogger provides a callback for flushing data buffered by the logger.
func FlushLogger(flush func()) LoggerOption {
	return func(o *loggerOptions) {
		o.flush = flush
	}
}

// WriteKlogBuffer sets a callback that will be invoked by klog to write output
// produced by non-structured log calls like Infof.
//
// The buffer will contain exactly the same data that klog normally would write
// into its own output stream(s). In particular this includes the header, if
// klog is configured to write one. The callback then can divert that data into
// its own output streams. The buffer may or may not end in a line break.
//
// Without such a callback, klog will call the logger's Info or Error method
// with just the message string (i.e. no header).
func WriteKlogBuffer(write func([]byte)) LoggerOption {
	return func(o *loggerOptions) {
		o.writeKlogBuffer = write
	}
}

// LoggerOption implements the functional parameter paradigm for
// SetLoggerWithOptions.
type LoggerOption func(o *loggerOptions)

type loggerOptions struct {
	contextualLogger bool
	flush            func()
	writeKlogBuffer  func([]byte)
}

// logWriter combines a logger (always set) with a write callback (optional).
type logWriter struct {
	Logger
	writeKlogBuffer func([]byte)
}

// ClearLogger removes a backing Logger implementation if one was set earlier
// with SetLogger.
//
// Modifying the logger is not thread-safe and should be done while no other
// goroutines invoke log calls, usually during program initialization.
func ClearLogger() {
	logging.logger = nil
	logging.loggerOptions = loggerOptions{}
}

// EnableContextualLogging controls whether contextual logging is enabled.
// By default it is enabled. When disabled, FromContext avoids looking up
// the logger in the context and always returns the global logger.
// LoggerWithValues, LoggerWithName, and NewContext become no-ops
// and return their input logger respectively context. This may be useful
// to avoid the additional overhead for contextual logging.
//
// This must be called during initialization before goroutines are started.
func EnableContextualLogging(enabled bool) {
	logging.contextualLoggingEnabled = enabled
}

// FromContext retrieves a logger set by the caller or, if not set,
// falls back to the program's global logger (a Logger instance or klog
// itself).
func FromContext(ctx context.Context) Logger {
	if logging.contextualLoggingEnabled {
		if logger, err := logr.FromContext(ctx); err == nil {
			return logger
		}
	}

	return Background()
}

// TODO can be used as a last resort by code that has no means of
// receiving a logger from its caller. FromContext or an explicit logger
// parameter should be used instead.
func TODO() Logger {
	return Background()
}

// Background retrieves the fallback logger. It should not be called before
// that logger was initialized by the program and not by code that should
// better receive a logger via its parameters. TODO can be used as a temporary
// solution for such code.
func Background() Logger {
	if logging.loggerOptions.contextualLogger {
		// Is non-nil because logging.loggerOptions.contextualLogger is
		// only true if a logger was set.
		return logging.logger.Logger
	}

	return klogLogger
}

// LoggerWithValues returns logger.WithValues(...kv) when
// contextual logging is enabled, otherwise the logger.
func LoggerWithValues(logger Logger, kv ...interface{}) Logger {
	if logging.contextualLoggingEnabled {
		return logger.WithValues(kv...)
	}
	return logger
}

// LoggerWithName returns logger.WithName(name) when contextual logging is
// enabled, otherwise the logger.
func LoggerWithName(logger Logger, name string) Logger {
	if logging.contextualLoggingEnabled {
		return logger.WithName(name)
	}
	return logger
}

// NewContext returns logr.NewContext(ctx, logger) when
// contextual logging is enabled, otherwise ctx.
func NewContext(ctx context.Context, logger Logger) context.Context {
	if logging.contextualLoggingEnabled {
		return logr.NewContext(ctx, logger)
	}
	return ctx
}


================================================
FILE: contextual_slog.go
================================================
//go:build go1.21
// +build go1.21

/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package klog

import (
	"log/slog"

	"github.com/go-logr/logr"
)

// SetSlogLogger reconfigures klog to log through the slog logger. The logger must not be nil.
func SetSlogLogger(logger *slog.Logger) {
	SetLoggerWithOptions(logr.FromSlogHandler(logger.Handler()), ContextualLogger(true))
}


================================================
FILE: contextual_slog_example_test.go
================================================
//go:build go1.21
// +build go1.21

/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package klog_test

import (
	"log/slog"
	"os"

	"k8s.io/klog/v2"
)

func ExampleSetSlogLogger() {
	state := klog.CaptureState()
	defer state.Restore()

	handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
		ReplaceAttr: func(_ /* groups */ []string, a slog.Attr) slog.Attr {
			if a.Key == slog.TimeKey {
				// Avoid non-deterministic output.
				return slog.Attr{}
			}
			return a
		},
	})
	logger := slog.New(handler)
	klog.SetSlogLogger(logger)
	klog.Info("hello world")

	// Output:
	// level=INFO msg="hello world"
}


================================================
FILE: contextual_test.go
================================================
/*
Copyright 2022 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package klog_test

import (
	"context"
	"fmt"
	"runtime"
	"testing"

	"github.com/go-logr/logr"
	"k8s.io/klog/v2"
)

func ExampleSetLogger() {
	defer klog.ClearLogger()

	// Logger is only used as backend, Background() returns klogr.
	klog.SetLogger(logr.Discard())
	fmt.Printf("logger after SetLogger: %T\n", klog.Background().GetSink())

	// Logger is only used as backend, Background() returns klogr.
	klog.SetLoggerWithOptions(logr.Discard(), klog.ContextualLogger(false))
	fmt.Printf("logger after SetLoggerWithOptions with ContextualLogger(false): %T\n", klog.Background().GetSink())

	// Logger is used as backend and directly.
	klog.SetLoggerWithOptions(logr.Discard(), klog.ContextualLogger(true))
	fmt.Printf("logger after SetLoggerWithOptions with ContextualLogger(true): %T\n", klog.Background().GetSink())

	// Output:
	// logger after SetLogger: *klog.klogger
	// logger after SetLoggerWithOptions with ContextualLogger(false): *klog.klogger
	// logger after SetLoggerWithOptions with ContextualLogger(true): <nil>
}

func ExampleFlushLogger() {
	defer klog.ClearLogger()

	// This simple logger doesn't need flushing, but others might.
	klog.SetLoggerWithOptions(logr.Discard(), klog.FlushLogger(func() {
		fmt.Print("flushing...")
	}))
	klog.Flush()

	// Output:
	// flushing...
}

func BenchmarkPassingLogger(b *testing.B) {
	b.Run("with context", func(b *testing.B) {
		ctx := klog.NewContext(context.Background(), klog.Background())
		var finalCtx context.Context
		for n := b.N; n > 0; n-- {
			finalCtx = passCtx(ctx)
		}
		runtime.KeepAlive(finalCtx)
	})

	b.Run("without context", func(b *testing.B) {
		logger := klog.Background()
		var finalLogger klog.Logger
		for n := b.N; n > 0; n-- {
			finalLogger = passLogger(logger)
		}
		runtime.KeepAlive(finalLogger)
	})
}

func BenchmarkExtractLogger(b *testing.B) {
	b.Run("from context", func(b *testing.B) {
		ctx := klog.NewContext(context.Background(), klog.Background())
		var finalLogger klog.Logger
		for n := b.N; n > 0; n-- {
			finalLogger = extractCtx(ctx)
		}
		runtime.KeepAlive(finalLogger)
	})
}

//go:noinline
func passCtx(ctx context.Context) context.Context { return ctx }

//go:noinline
func extractCtx(ctx context.Context) klog.Logger { return klog.FromContext(ctx) }

//go:noinline
func passLogger(logger klog.Logger) klog.Logger { return logger }


================================================
FILE: examples/benchmarks/benchmarks_test.go
================================================
/*
Copyright 2022 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package benchmarks

import (
	"flag"
	"fmt"
	"io"
	"testing"

	"github.com/go-logr/logr"
	"github.com/go-logr/zapr"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"

	"k8s.io/klog/examples/util/require"
	"k8s.io/klog/v2"
)

const (
	verbosityThreshold = 10
)

func init() {
	// klog gets configured so that it writes to a single output file that
	// will be set during tests with SetOutput.
	klog.InitFlags(nil)
	require.NoError(flag.Set("v", fmt.Sprintf("%d", verbosityThreshold)))
	require.NoError(flag.Set("log_file", "/dev/null"))
	require.NoError(flag.Set("logtostderr", "false"))
	require.NoError(flag.Set("alsologtostderr", "false"))
	require.NoError(flag.Set("stderrthreshold", "10"))
}

type testcase struct {
	name     string
	generate func() interface{}
}

func BenchmarkOutput(b *testing.B) {
	// We'll run each benchmark for different output formatting.
	configs := map[string]struct {
		init, cleanup func()
	}{
		"klog": {
			init: func() { klog.SetOutput(discard{}) },
		},
		"zapr": {
			init:    func() { klog.SetLogger(newZaprLogger()) },
			cleanup: func() { klog.ClearLogger() },
		},
	}

	// Each benchmark tests formatting of one key/value pair, with
	// different values. The order is relevant here.
	var tests []testcase
	for length := 0; length <= 100; length += 10 {
		arg := make([]interface{}, length)
		for i := 0; i < length; i++ {
			arg[i] = KMetadataMock{Name: "a", NS: "a"}
		}
		tests = append(tests, testcase{
			name: fmt.Sprintf("objects/%d", length),
			generate: func() interface{} {
				return klog.KObjSlice(arg)
			},
		})
	}

	// Verbosity checks may influence the result.
	verbosity := map[string]func(value interface{}){
		"no-verbosity-check": func(value interface{}) {
			klog.InfoS("test", "key", value)
		},
		"pass-verbosity-check": func(value interface{}) {
			klog.V(verbosityThreshold).InfoS("test", "key", value)
		},
		"fail-verbosity-check": func(value interface{}) {
			klog.V(verbosityThreshold+1).InfoS("test", "key", value)
		},
		"non-standard-int-key-check": func(value interface{}) {
			klog.InfoS("test", 1, value)
		},
		"non-standard-struct-key-check": func(value interface{}) {
			klog.InfoS("test", struct{ key string }{"test"}, value)
		},
		"non-standard-map-key-check": func(value interface{}) {
			klog.InfoS("test", map[string]bool{"key": true}, value)
		},
		"pass-verbosity-non-standard-int-key-check": func(value interface{}) {
			klog.V(verbosityThreshold).InfoS("test", 1, value)
		},
		"pass-verbosity-non-standard-struct-key-check": func(value interface{}) {
			klog.V(verbosityThreshold).InfoS("test", struct{ key string }{"test"}, value)
		},
		"pass-verbosity-non-standard-map-key-check": func(value interface{}) {
			klog.V(verbosityThreshold).InfoS("test", map[string]bool{"key": true}, value)
		},
		"fail-verbosity-non-standard-int-key-check": func(value interface{}) {
			klog.V(verbosityThreshold+1).InfoS("test", 1, value)
		},
		"fail-verbosity-non-standard-struct-key-check": func(value interface{}) {
			klog.V(verbosityThreshold+1).InfoS("test", struct{ key string }{"test"}, value)
		},
		"fail-verbosity-non-standard-map-key-check": func(value interface{}) {
			klog.V(verbosityThreshold+1).InfoS("test", map[string]bool{"key": true}, value)
		},
	}

	for name, config := range configs {
		b.Run(name, func(b *testing.B) {
			if config.cleanup != nil {
				defer config.cleanup()
			}
			config.init()

			for name, logCall := range verbosity {
				b.Run(name, func(b *testing.B) {
					for _, testcase := range tests {
						b.Run(testcase.name, func(b *testing.B) {
							b.ResetTimer()
							for i := 0; i < b.N; i++ {
								logCall(testcase.generate())
							}
						})
					}
				})
			}
		})
	}
}

func newZaprLogger() logr.Logger {
	encoderConfig := &zapcore.EncoderConfig{
		MessageKey:     "msg",
		CallerKey:      "caller",
		NameKey:        "logger",
		EncodeDuration: zapcore.StringDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
	encoder := zapcore.NewJSONEncoder(*encoderConfig)
	zapV := -zapcore.Level(verbosityThreshold)
	core := zapcore.NewCore(encoder, zapcore.AddSync(discard{}), zapV)
	l := zap.New(core, zap.WithCaller(true))
	logger := zapr.NewLoggerWithOptions(l, zapr.LogInfoLevel("v"), zapr.ErrorKey("err"))
	return logger
}

type KMetadataMock struct {
	Name, NS string
}

func (m KMetadataMock) GetName() string {
	return m.Name
}
func (m KMetadataMock) GetNamespace() string {
	return m.NS
}

type discard struct{}

var _ io.Writer = discard{}

func (discard) Write(p []byte) (int, error) {
	return len(p), nil
}


================================================
FILE: examples/coexist_glog/coexist_glog.go
================================================
package main

import (
	"flag"

	"github.com/golang/glog"
	"k8s.io/klog/examples/util/require"
	"k8s.io/klog/v2"
)

func main() {
	require.NoError(flag.Set("alsologtostderr", "true"))
	flag.Parse()

	klogFlags := flag.NewFlagSet("klog", flag.ExitOnError)
	klog.InitFlags(klogFlags)

	// Sync the glog and klog flags.
	flag.CommandLine.VisitAll(func(f1 *flag.Flag) {
		f2 := klogFlags.Lookup(f1.Name)
		if f2 != nil {
			value := f1.Value.String()
			require.NoError(f2.Value.Set(value))
		}
	})

	glog.Info("hello from glog!")
	klog.Info("nice to meet you, I'm klog")
	glog.Flush()
	klog.Flush()
}


================================================
FILE: examples/coexist_klog_v1_and_v2/coexist_klog_v1_and_v2.go
================================================
package main

import (
	"flag"

	klogv1 "k8s.io/klog"
	klogv2 "k8s.io/klog/v2"
)

// OutputCallDepth is the stack depth where we can find the origin of this call
const OutputCallDepth = 6

// DefaultPrefixLength is the length of the log prefix that we have to strip out
const DefaultPrefixLength = 53

// klogWriter is used in SetOutputBySeverity call below to redirect
// any calls to klogv1 to end up in klogv2
type klogWriter struct{}

func (kw klogWriter) Write(p []byte) (n int, err error) {
	if len(p) < DefaultPrefixLength {
		klogv2.InfoDepth(OutputCallDepth, string(p))
		return len(p), nil
	}
	if p[0] == 'I' {
		klogv2.InfoDepth(OutputCallDepth, string(p[DefaultPrefixLength:]))
	} else if p[0] == 'W' {
		klogv2.WarningDepth(OutputCallDepth, string(p[DefaultPrefixLength:]))
	} else if p[0] == 'E' {
		klogv2.ErrorDepth(OutputCallDepth, string(p[DefaultPrefixLength:]))
	} else if p[0] == 'F' {
		klogv2.FatalDepth(OutputCallDepth, string(p[DefaultPrefixLength:]))
	} else {
		klogv2.InfoDepth(OutputCallDepth, string(p[DefaultPrefixLength:]))
	}
	return len(p), nil
}

func main() {
	// initialize klog/v2, can also bind to a local flagset if desired
	klogv2.InitFlags(nil)

	// In this example, we want to show you that all the lines logged
	// end up in the myfile.log. You do NOT need them in your application
	// as all these flags are set up from the command line typically
	flag.Set("logtostderr", "false")     // By default klog logs to stderr, switch that off
	flag.Set("alsologtostderr", "false") // false is default, but this is informative
	flag.Set("stderrthreshold", "FATAL") // stderrthreshold defaults to ERROR, we don't want anything in stderr
	flag.Set("log_file", "myfile.log")   // log to a file

	// parse klog/v2 flags
	flag.Parse()
	// make sure we flush before exiting
	defer klogv2.Flush()

	// BEGIN : hack to redirect klogv1 calls to klog v2
	// Tell klog NOT to log into STDERR. Otherwise, we risk
	// certain kinds of API errors getting logged into a directory not
	// available in a `FROM scratch` Docker container, causing us to abort
	var klogv1Flags flag.FlagSet
	klogv1.InitFlags(&klogv1Flags)
	klogv1Flags.Set("logtostderr", "false")     // By default klog v1 logs to stderr, switch that off
	klogv1Flags.Set("stderrthreshold", "FATAL") // stderrthreshold defaults to ERROR, use this if you
	// don't want anything in your stderr

	klogv1.SetOutputBySeverity("INFO", klogWriter{}) // tell klog v1 to use the writer
	// END : hack to redirect klogv1 calls to klog v2

	// Now you can mix klogv1 and v2 in the same code base
	klogv2.Info("hello from klog (v2)!")
	klogv1.Info("hello from klog (v1)!")
	klogv1.Warning("beware from klog (v1)!")
	klogv1.Error("error from klog (v1)!")
	klogv2.Info("nice to meet you (v2)")
}


================================================
FILE: examples/coexist_klog_v1_and_v2/go.mod
================================================
module k8s.io/klog/examples/coexist_klog_v1_and_v2

go 1.13

require (
	k8s.io/klog v1.0.0
	k8s.io/klog/v2 v2.0.0
)


================================================
FILE: examples/flushing/.gitignore
================================================
myfile.log


================================================
FILE: examples/flushing/flushing_test.go
================================================
package main

import (
	"flag"
	"testing"

	"go.uber.org/goleak"

	"k8s.io/klog/examples/util/require"
	"k8s.io/klog/v2"
)

func main() {
	klog.InitFlags(nil)

	// By default klog writes to stderr. Setting logtostderr to false makes klog
	// write to a log file.
	require.NoError(flag.Set("logtostderr", "false"))
	require.NoError(flag.Set("log_file", "myfile.log"))
	flag.Parse()

	// Info writes the first log message. When the first log file is created,
	// a flushDaemon is started to frequently flush bytes to the file.
	klog.Info("nice to meet you")

	// klog won't ever stop this flushDaemon. To exit without leaking a goroutine,
	// the daemon can be stopped manually.
	klog.StopFlushDaemon()

	// After you stopped the flushDaemon, you can still manually flush.
	klog.Info("bye")
	klog.Flush()
}

func TestLeakingFlushDaemon(t *testing.T) {
	// goleak detects leaking goroutines.
	defer goleak.VerifyNone(t)

	// Without calling StopFlushDaemon in main, this test will fail.
	main()
}


================================================
FILE: examples/go.mod
================================================
module k8s.io/klog/examples

go 1.22.0

toolchain go1.23.0

require (
	github.com/go-logr/logr v1.4.1
	github.com/go-logr/zapr v1.2.3
	github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
	go.uber.org/goleak v1.1.12
	go.uber.org/zap v1.19.0
	golang.org/x/tools v0.27.0
	k8s.io/klog/v2 v2.30.0
)

require (
	go.uber.org/atomic v1.7.0 // indirect
	go.uber.org/multierr v1.6.0 // indirect
	golang.org/x/mod v0.22.0 // indirect
	golang.org/x/sync v0.9.0 // indirect
)

replace k8s.io/klog/v2 => ../


================================================
FILE: examples/go.sum
================================================
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE=
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=


================================================
FILE: examples/go_vet/go_vet_test.go
================================================
/*
Copyright 2023 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"os"
	"os/exec"
	"path"
	"testing"

	"golang.org/x/tools/go/analysis/analysistest"
	"golang.org/x/tools/go/analysis/passes/printf"
)

// TestGoVet checks that "go vet" detects incorrect klog calls like
// mismatched format specifiers and arguments.
func TestGoVet(t *testing.T) {
	testdata := analysistest.TestData()
	src := path.Join(testdata, "src")
	t.Cleanup(func() {
		os.RemoveAll(src)
	})

	// analysistest doesn't support using existing code
	// via modules (https://github.com/golang/go/issues/37054).
	// Populating the "testdata/src" directory with the
	// result of "go mod vendor" is a workaround.
	cmd := exec.Command("go", "mod", "vendor", "-o", src)
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("%s failed: %v\nOutput: %s", cmd, err, string(out))
	}

	analyzer := printf.Analyzer
	analysistest.Run(t, testdata, analyzer, "")
}


================================================
FILE: examples/go_vet/testdata/calls.go
================================================
/*
Copyright 2023 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package testdata

import (
	"k8s.io/klog/v2"
)

func calls() {
	klog.Infof("%s") // want `k8s.io/klog/v2.Infof format %s reads arg #1, but call has 0 args`
	klog.Infof("%s", "world")
	klog.Info("%s", "world") // want `k8s.io/klog/v2.Info call has possible Printf formatting directive %s`
	klog.Info("world")
	klog.Infoln("%s", "world") // want `k8s.io/klog/v2.Infoln call has possible Printf formatting directive %s`
	klog.Infoln("world")

	klog.InfofDepth(1, "%s") // want `k8s.io/klog/v2.InfofDepth format %s reads arg #1, but call has 0 args`
	klog.InfofDepth(1, "%s", "world")
	klog.InfoDepth(1, "%s", "world") // want `k8s.io/klog/v2.InfoDepth call has possible Printf formatting directive %s`
	klog.InfoDepth(1, "world")
	klog.InfolnDepth(1, "%s", "world") // want `k8s.io/klog/v2.InfolnDepth call has possible Printf formatting directive %s`
	klog.InfolnDepth(1, "world")

	klog.Warningf("%s") // want `k8s.io/klog/v2.Warningf format %s reads arg #1, but call has 0 args`
	klog.Warningf("%s", "world")
	klog.Warning("%s", "world") // want `k8s.io/klog/v2.Warning call has possible Printf formatting directive %s`
	klog.Warning("world")
	klog.Warningln("%s", "world") // want `k8s.io/klog/v2.Warningln call has possible Printf formatting directive %s`
	klog.Warningln("world")

	klog.WarningfDepth(1, "%s") // want `k8s.io/klog/v2.WarningfDepth format %s reads arg #1, but call has 0 args`
	klog.WarningfDepth(1, "%s", "world")
	klog.WarningDepth(1, "%s", "world") // want `k8s.io/klog/v2.WarningDepth call has possible Printf formatting directive %s`
	klog.WarningDepth(1, "world")
	klog.WarninglnDepth(1, "%s", "world") // want `k8s.io/klog/v2.WarninglnDepth call has possible Printf formatting directive %s`
	klog.WarninglnDepth(1, "world")

	klog.Errorf("%s") // want `k8s.io/klog/v2.Errorf format %s reads arg #1, but call has 0 args`
	klog.Errorf("%s", "world")
	klog.Error("%s", "world") // want `k8s.io/klog/v2.Error call has possible Printf formatting directive %s`
	klog.Error("world")
	klog.Errorln("%s", "world") // want `k8s.io/klog/v2.Errorln call has possible Printf formatting directive %s`
	klog.Errorln("world")

	klog.ErrorfDepth(1, "%s") // want `k8s.io/klog/v2.ErrorfDepth format %s reads arg #1, but call has 0 args`
	klog.ErrorfDepth(1, "%s", "world")
	klog.ErrorDepth(1, "%s", "world") // want `k8s.io/klog/v2.ErrorDepth call has possible Printf formatting directive %s`
	klog.ErrorDepth(1, "world")
	klog.ErrorlnDepth(1, "%s", "world") // want `k8s.io/klog/v2.ErrorlnDepth call has possible Printf formatting directive %s`
	klog.ErrorlnDepth(1, "world")

	klog.Fatalf("%s") // want `k8s.io/klog/v2.Fatalf format %s reads arg #1, but call has 0 args`
	klog.Fatalf("%s", "world")
	klog.Fatal("%s", "world") // want `k8s.io/klog/v2.Fatal call has possible Printf formatting directive %s`
	klog.Fatal("world")
	klog.Fatalln("%s", "world") // want `k8s.io/klog/v2.Fatalln call has possible Printf formatting directive %s`
	klog.Fatalln("world")

	klog.FatalfDepth(1, "%s") // want `k8s.io/klog/v2.FatalfDepth format %s reads arg #1, but call has 0 args`
	klog.FatalfDepth(1, "%s", "world")
	klog.FatalDepth(1, "%s", "world") // want `k8s.io/klog/v2.FatalDepth call has possible Printf formatting directive %s`
	klog.FatalDepth(1, "world")
	klog.FatallnDepth(1, "%s", "world") // want `k8s.io/klog/v2.FatallnDepth call has possible Printf formatting directive %s`
	klog.FatallnDepth(1, "world")

	klog.V(1).Infof("%s") // want `\(k8s.io/klog/v2.Verbose\).Infof format %s reads arg #1, but call has 0 args`
	klog.V(1).Infof("%s", "world")
	klog.V(1).Info("%s", "world") // want `\(k8s.io/klog/v2.Verbose\).Info call has possible Printf formatting directive %s`
	klog.V(1).Info("world")
	klog.V(1).Infoln("%s", "world") // want `\(k8s.io/klog/v2.Verbose\).Infoln call has possible Printf formatting directive %s`
	klog.V(1).Infoln("world")

	klog.V(1).InfofDepth(1, "%s") // want `\(k8s.io/klog/v2.Verbose\).InfofDepth format %s reads arg #1, but call has 0 args`
	klog.V(1).InfofDepth(1, "%s", "world")
	klog.V(1).InfoDepth(1, "%s", "world") // want `\(k8s.io/klog/v2.Verbose\).InfoDepth call has possible Printf formatting directive %s`
	klog.V(1).InfoDepth(1, "world")
	klog.V(1).InfolnDepth(1, "%s", "world") // want `\(k8s.io/klog/v2.Verbose\).InfolnDepth call has possible Printf formatting directive %s`
	klog.V(1).InfolnDepth(1, "world")

	// Detecting format specifiers for klog.InfoS and other structured logging calls would be nice,
	// but doesn't work the same way because of the extra "msg" string parameter. logcheck
	// can be used instead of "go vet".
	klog.InfoS("%s", "world")
}


================================================
FILE: examples/klogr/main.go
================================================
package main

import (
	"flag"

	"k8s.io/klog/examples/util/require"
	"k8s.io/klog/v2"
	"k8s.io/klog/v2/klogr"
)

type myError struct {
	str string
}

func (e myError) Error() string {
	return e.str
}

func main() {
	klog.InitFlags(nil)
	require.NoError(flag.Set("v", "3"))
	flag.Parse()
	log := klogr.New().WithName("MyName").WithValues("user", "you")
	log.Info("hello", "val1", 1, "val2", map[string]int{"k": 1})
	log.V(3).Info("nice to meet you")
	log.Error(nil, "uh oh", "trouble", true, "reasons", []float64{0.1, 0.11, 3.14})
	log.Error(myError{"an error occurred"}, "goodbye", "code", -1)
	klog.Flush()
}


================================================
FILE: examples/log_file/usage_log_file.go
================================================
package main

import (
	"flag"

	"k8s.io/klog/examples/util/require"
	"k8s.io/klog/v2"
)

func main() {
	klog.InitFlags(nil)
	// By default klog writes to stderr. Setting logtostderr to false makes klog
	// write to a log file.
	require.NoError(flag.Set("logtostderr", "false"))
	require.NoError(flag.Set("log_file", "myfile.log"))
	flag.Parse()
	klog.Info("nice to meet you")
	klog.Flush()
}


================================================
FILE: examples/output_test/output_test.go
================================================
/*
Copyright 2022 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package output_test shows how to use k8s.io/klog/v2/test
// and provides unit testing with dependencies that wouldn't
// be acceptable for the main module.
package output_test

import (
	"io"
	"testing"

	"github.com/go-logr/logr"
	"github.com/go-logr/zapr"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"

	"k8s.io/klog/v2"
	"k8s.io/klog/v2/klogr"
	"k8s.io/klog/v2/test"
	"k8s.io/klog/v2/textlogger"
)

// newLogger is a test.OutputConfig.NewLogger callback which creates a zapr
// logger. The vmodule parameter is ignored because zapr does not support that.
func newLogger(out io.Writer, v int, _ string) logr.Logger {
	return newZaprLogger(out, v)
}

// TestZaprOutput tests the zapr, directly and as backend.
func TestZaprOutput(t *testing.T) {
	test.InitKlog(t)
	t.Run("direct", func(t *testing.T) {
		test.Output(t, test.OutputConfig{NewLogger: newLogger, ExpectedOutputMapping: test.ZaprOutputMappingDirect()})
	})
	t.Run("klog-backend", func(t *testing.T) {
		test.Output(t, test.OutputConfig{NewLogger: newLogger, AsBackend: true, ExpectedOutputMapping: test.ZaprOutputMappingIndirect()})
	})
}

// Benchmark direct zapr output.
func BenchmarkZaprOutput(b *testing.B) {
	test.InitKlog(b)
	test.Benchmark(b, test.OutputConfig{NewLogger: newLogger, ExpectedOutputMapping: test.ZaprOutputMappingDirect()})
}

// TestKlogrStackText tests klogr.klogr -> klog -> text logger.
func TestKlogrStackText(t *testing.T) {
	test.InitKlog(t)
	newLogger := func(out io.Writer, v int, vmodule string) logr.Logger {
		// Backend: text output.
		config := textlogger.NewConfig(
			textlogger.Verbosity(v),
			textlogger.Output(out),
		)
		if err := config.VModule().Set(vmodule); err != nil {
			panic(err)
		}
		klog.SetLogger(textlogger.NewLogger(config))

		// Frontend: klogr.
		return klogr.NewWithOptions(klogr.WithFormat(klogr.FormatKlog))
	}
	test.Output(t, test.OutputConfig{NewLogger: newLogger, SupportsVModule: true})
}

// TestKlogrStackKlogr tests klogr.klogr -> klog -> zapr.
//
// This exposes whether verbosity is passed through correctly
// (https://github.com/kubernetes/klog/issues/294) because klogr logging
// records that.
func TestKlogrStackZapr(t *testing.T) {
	test.InitKlog(t)
	mapping := test.ZaprOutputMappingIndirect()

	// klogr doesn't warn about invalid KVs and just inserts
	// "(MISSING)".
	for key, value := range map[string]string{
		`I output.go:<LINE>] "odd arguments" akey="avalue" akey2="(MISSING)"
`: `{"caller":"test/output.go:<LINE>","msg":"odd arguments","v":0,"akey":"avalue","akey2":"(MISSING)"}
`,

		`I output.go:<LINE>] "both odd" basekey1="basevar1" basekey2="(MISSING)" akey="avalue" akey2="(MISSING)"
`: `{"caller":"test/output.go:<LINE>","msg":"both odd","v":0,"basekey1":"basevar1","basekey2":"(MISSING)","akey":"avalue","akey2":"(MISSING)"}
`,
		`I output.go:<LINE>] "integer keys" %!s(int=1)="value" %!s(int=2)="value2" akey="avalue" akey2="(MISSING)"
`: `{"caller":"test/output.go:<LINE>","msg":"non-string key argument passed to logging, ignoring all later arguments","invalid key":1}
{"caller":"test/output.go:<LINE>","msg":"integer keys","v":0}
`,
		`I output.go:<LINE>] "struct keys" {name}="value" test="other value" key="val"
`: `{"caller":"test/output.go:<LINE>","msg":"non-string key argument passed to logging, ignoring all later arguments","invalid key":{}}
{"caller":"test/output.go:<LINE>","msg":"struct keys","v":0}
`,
		`I output.go:<LINE>] "map keys" map[test:%!s(bool=true)]="test"
`: `{"caller":"test/output.go:<LINE>","msg":"non-string key argument passed to logging, ignoring all later arguments","invalid key":{"test":true}}
{"caller":"test/output.go:<LINE>","msg":"map keys","v":0}
`,
	} {
		mapping[key] = value
	}

	newLogger := func(out io.Writer, v int, _ string) logr.Logger {
		// Backend: zapr as configured in k8s.io/component-base/logs/json.
		klog.SetLogger(newZaprLogger(out, v))

		// Frontend: klogr.
		return klogr.NewWithOptions(klogr.WithFormat(klogr.FormatKlog))
	}
	test.Output(t, test.OutputConfig{NewLogger: newLogger, ExpectedOutputMapping: mapping})
}

// TestKlogrInternalStackText tests klog.klogr (the simplified version used for contextual logging) -> klog -> text logger.
func TestKlogrInternalStackText(t *testing.T) {
	test.InitKlog(t)
	newLogger := func(out io.Writer, v int, vmodule string) logr.Logger {
		// Backend: text output.
		config := textlogger.NewConfig(
			textlogger.Verbosity(v),
			textlogger.Output(out),
		)
		if err := config.VModule().Set(vmodule); err != nil {
			panic(err)
		}
		klog.SetLogger(textlogger.NewLogger(config))

		// Frontend: internal klogr.
		return klog.NewKlogr()
	}
	test.Output(t, test.OutputConfig{NewLogger: newLogger, SupportsVModule: true})
}

// TestKlogrInternalStackKlogr tests klog.klogr (the simplified version used for contextual logging) -> klog -> zapr.
//
// This exposes whether verbosity is passed through correctly
// (https://github.com/kubernetes/klog/issues/294) because klogr logging
// records that.
func TestKlogrInternalStackZapr(t *testing.T) {
	test.InitKlog(t)
	mapping := test.ZaprOutputMappingIndirect()

	// klogr doesn't warn about invalid KVs and just inserts
	// "(MISSING)".
	for key, value := range map[string]string{
		`I output.go:<LINE>] "odd arguments" akey="avalue" akey2="(MISSING)"
`: `{"caller":"test/output.go:<LINE>","msg":"odd arguments","v":0,"akey":"avalue","akey2":"(MISSING)"}
`,

		`I output.go:<LINE>] "both odd" basekey1="basevar1" basekey2="(MISSING)" akey="avalue" akey2="(MISSING)"
`: `{"caller":"test/output.go:<LINE>","msg":"both odd","v":0,"basekey1":"basevar1","basekey2":"(MISSING)","akey":"avalue","akey2":"(MISSING)"}
`,
		`I output.go:<LINE>] "integer keys" %!s(int=1)="value" %!s(int=2)="value2" akey="avalue" akey2="(MISSING)"
`: `{"caller":"test/output.go:<LINE>","msg":"non-string key argument passed to logging, ignoring all later arguments","invalid key":1}
{"caller":"test/output.go:<LINE>","msg":"integer keys","v":0}
`,
		`I output.go:<LINE>] "struct keys" {name}="value" test="other value" key="val"
`: `{"caller":"test/output.go:<LINE>","msg":"non-string key argument passed to logging, ignoring all later arguments","invalid key":{}}
{"caller":"test/output.go:<LINE>","msg":"struct keys","v":0}
`,
		`I output.go:<LINE>] "map keys" map[test:%!s(bool=true)]="test"
`: `{"caller":"test/output.go:<LINE>","msg":"non-string key argument passed to logging, ignoring all later arguments","invalid key":{"test":true}}
{"caller":"test/output.go:<LINE>","msg":"map keys","v":0}
`,
	} {
		mapping[key] = value
	}

	newLogger := func(out io.Writer, v int, _ string) logr.Logger {
		// Backend: zapr as configured in k8s.io/component-base/logs/json.
		klog.SetLogger(newZaprLogger(out, v))

		// Frontend: internal klogr.
		return klog.NewKlogr()
	}
	test.Output(t, test.OutputConfig{NewLogger: newLogger, ExpectedOutputMapping: mapping})
}

func newZaprLogger(out io.Writer, v int) logr.Logger {
	encoderConfig := &zapcore.EncoderConfig{
		MessageKey:     "msg",
		CallerKey:      "caller",
		NameKey:        "logger",
		EncodeDuration: zapcore.StringDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
	encoder := zapcore.NewJSONEncoder(*encoderConfig)
	zapV := -zapcore.Level(v)
	core := zapcore.NewCore(encoder, zapcore.AddSync(out), zapV)
	l := zap.New(core, zap.WithCaller(true))
	logger := zapr.NewLoggerWithOptions(l, zapr.LogInfoLevel("v"), zapr.ErrorKey("err"))
	return logger
}


================================================
FILE: examples/set_output/usage_set_output.go
================================================
package main

import (
	"bytes"
	"flag"
	"fmt"

	"k8s.io/klog/examples/util/require"
	"k8s.io/klog/v2"
)

func main() {
	klog.InitFlags(nil)
	require.NoError(flag.Set("logtostderr", "false"))
	require.NoError(flag.Set("alsologtostderr", "false"))
	flag.Parse()

	buf := new(bytes.Buffer)
	klog.SetOutput(buf)
	klog.Info("nice to meet you")
	klog.Flush()

	fmt.Printf("LOGGED: %s", buf.String())
}


================================================
FILE: examples/stderr_threshold_fix/main.go
================================================
// Example demonstrating the new stderr threshold behavior
package main

import (
	"flag"

	"k8s.io/klog/v2"
)

func main() {
	klog.InitFlags(nil)
	flag.Parse()

	klog.Info("This is an INFO message")
	klog.Warning("This is a WARNING message")
	klog.Error("This is an ERROR message")

	klog.Flush()
}

// Run examples:
//
// 1. Legacy behavior (default) - all logs to stderr:
//    go run main.go -logtostderr=true -stderrthreshold=ERROR
//    Result: All three messages appear
//
// 2. New behavior - filter by severity:
//    go run main.go -logtostderr=true -legacy_stderr_threshold_behavior=false -stderrthreshold=ERROR
//    Result: Only ERROR message appears
//
// 3. New behavior - show WARNING and above:
//    go run main.go -logtostderr=true -legacy_stderr_threshold_behavior=false -stderrthreshold=WARNING
//    Result: WARNING and ERROR messages appear
//
// 4. Using alsologtostderrthreshold with file logging:
//    go run main.go -logtostderr=false -alsologtostderr=true -alsologtostderrthreshold=ERROR -log_dir=/tmp/logs
//    Result: All logs in files, only ERROR to stderr


================================================
FILE: examples/structured_logging/structured_logging.go
================================================
package main

import (
	"flag"

	"k8s.io/klog/v2"
)

// MyStruct will be logged via %+v
type MyStruct struct {
	Name     string
	Data     string
	internal int
}

// MyStringer will be logged as string, with String providing that string.
type MyString MyStruct

func (m MyString) String() string {
	return m.Name + ": " + m.Data
}

func main() {
	klog.InitFlags(nil)
	flag.Parse()

	someData := MyStruct{
		Name:     "hello",
		Data:     "world",
		internal: 42,
	}

	longData := MyStruct{
		Name: "long",
		Data: `Multiple
lines
with quite a bit
of text.`,
	}

	logData := MyStruct{
		Name: "log output from some program",
		Data: `I0000 12:00:00.000000  123456 main.go:42] Starting
E0000 12:00:01.000000  123456 main.go:43] Failed for some reason
`,
	}

	stringData := MyString(longData)

	klog.Infof("someData printed using InfoF: %v", someData)
	klog.Infof("longData printed using InfoF: %v", longData)
	klog.Infof(`stringData printed using InfoF,
with the message across multiple lines:
%v`, stringData)
	klog.Infof("logData printed using InfoF:\n%v", logData)

	klog.Info("=============================================")

	klog.InfoS("using InfoS", "someData", someData)
	klog.InfoS("using InfoS", "longData", longData)
	klog.InfoS(`using InfoS with
the message across multiple lines`,
		"int", 1,
		"stringData", stringData,
		"str", "another value")
	klog.InfoS("using InfoS", "logData", logData)
	klog.InfoS("using InfoS", "boolean", true, "int", 1, "float", 0.1)

	// The Kubernetes recommendation is to start the message with uppercase
	// and not end with punctuation. See
	// https://github.com/kubernetes/community/blob/HEAD/contributors/devel/sig-instrumentation/migration-to-structured-logging.md
	klog.InfoS("Did something", "item", "foobar")
	// Not recommended, but also works.
	klog.InfoS("This is a full sentence.", "item", "foobar")
}


================================================
FILE: examples/util/require/require.go
================================================
package require

func NoError(err error) {
	if err != nil {
		panic(err)
	}
}


================================================
FILE: exit.go
================================================
// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
//
// Copyright 2013 Google Inc. All Rights Reserved.
// Copyright 2022 The Kubernetes Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package klog

import (
	"fmt"
	"os"
	"time"
)

var (

	// ExitFlushTimeout is the timeout that klog has traditionally used during
	// calls like Fatal or Exit when flushing log data right before exiting.
	// Applications that replace those calls and do not have some specific
	// requirements like "exit immediately" can use this value as parameter
	// for FlushAndExit.
	//
	// Can be set for testing purpose or to change the application's
	// default.
	ExitFlushTimeout = 10 * time.Second

	// OsExit is the function called by FlushAndExit to terminate the program.
	//
	// Can be set for testing purpose or to change the application's
	// default behavior. Note that the function should not simply return
	// because callers of functions like Fatal will not expect that.
	OsExit = os.Exit
)

// FlushAndExit flushes log data for a certain amount of time and then calls
// os.Exit. Combined with some logging call it provides a replacement for
// traditional calls like Fatal or Exit.
func FlushAndExit(flushTimeout time.Duration, exitCode int) {
	timeoutFlush(flushTimeout)
	OsExit(exitCode)
}

// timeoutFlush calls Flush and returns when it completes or after timeout
// elapses, whichever happens first.  This is needed because the hooks invoked
// by Flush may deadlock when klog.Fatal is called from a hook that holds
// a lock. Flushing also might take too long.
func timeoutFlush(timeout time.Duration) {
	done := make(chan bool, 1)
	go func() {
		Flush() // calls logging.lockAndFlushAll()
		done <- true
	}()
	select {
	case <-done:
	case <-time.After(timeout):
		fmt.Fprintln(os.Stderr, "klog: Flush took longer than", timeout)
	}
}


================================================
FILE: exit_test.go
================================================
// Copyright 2022 The Kubernetes Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package klog_test

import (
	"flag"
	"fmt"
	"os"

	"k8s.io/klog/v2"
)

func ExampleFlushAndExit() {
	// Set up klog so that we can test it below.

	var fs flag.FlagSet
	klog.InitFlags(&fs)
	state := klog.CaptureState()
	defer state.Restore()
	if err := fs.Set("skip_headers", "true"); err != nil {
		panic(err)
	}
	if err := fs.Set("logtostderr", "false"); err != nil {
		panic(err)
	}
	klog.SetOutput(os.Stdout)
	klog.OsExit = func(exitCode int) {
		fmt.Printf("os.Exit(%d)\n", exitCode)
	}

	// If we were to return or exit without flushing, this message would
	// get lost because it is buffered in memory by klog when writing to
	// files. Output to stderr is not buffered.
	klog.InfoS("exiting...")
	exitCode := 10
	klog.FlushAndExit(klog.ExitFlushTimeout, exitCode)

	// Output:
	// "exiting..."
	// os.Exit(10)
}


================================================
FILE: format.go
================================================
/*
Copyright 2023 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package klog

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/go-logr/logr"
)

// Format wraps a value of an arbitrary type and implement fmt.Stringer and
// logr.Marshaler for them. Stringer returns pretty-printed JSON. MarshalLog
// returns the original value with a type that has no special methods, in
// particular no MarshalLog or MarshalJSON.
//
// Wrapping values like that is useful when the value has a broken
// implementation of these special functions (for example, a type which
// inherits String from TypeMeta, but then doesn't re-implement String) or the
// implementation produces output that is less readable or unstructured (for
// example, the generated String functions for Kubernetes API types).
func Format(obj interface{}) interface{} {
	return formatAny{Object: obj}
}

type formatAny struct {
	Object interface{}
}

func (f formatAny) String() string {
	var buffer strings.Builder
	encoder := json.NewEncoder(&buffer)
	encoder.SetIndent("", "  ")
	if err := encoder.Encode(&f.Object); err != nil {
		return fmt.Sprintf("error marshaling %T to JSON: %v", f, err)
	}
	return buffer.String()
}

func (f formatAny) MarshalLog() interface{} {
	// Returning a pointer to a pointer ensures that zapr doesn't find a
	// fmt.Stringer or logr.Marshaler when it checks the type of the
	// value. It then falls back to reflection, which dumps the value being
	// pointed to (JSON doesn't have pointers).
	ptr := &f.Object
	return &ptr
}

var _ fmt.Stringer = formatAny{}
var _ logr.Marshaler = formatAny{}


================================================
FILE: format_test.go
================================================
/*
Copyright 2023 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package klog_test

import (
	"encoding/json"
	"fmt"
	"strings"
	"testing"

	"k8s.io/klog/v2"

	"github.com/go-logr/logr"
)

func TestFormat(t *testing.T) {
	obj := config{
		TypeMeta: TypeMeta{
			Kind: "config",
		},
		RealField: 42,
	}

	assertEqual(t, "kind is config", obj.String(), "config.String()")
	assertEqual(t, `{
  "Kind": "config",
  "RealField": 42
}
`, klog.Format(obj).(fmt.Stringer).String(), "Format(config).String()")
	// fmt.Sprintf would call String if it was available.
	str := fmt.Sprintf("%s", klog.Format(obj).(logr.Marshaler).MarshalLog())
	if strings.Contains(str, "kind is config") {
		t.Errorf("fmt.Sprintf called TypeMeta.String for klog.Format(obj).MarshalLog():\n%s", str)
	}

	structured, err := json.Marshal(klog.Format(obj).(logr.Marshaler).MarshalLog())
	if err != nil {
		t.Errorf("JSON Marshal: %v", err)
	} else {
		assertEqual(t, `{"Kind":"config","RealField":42}`, string(structured), "json.Marshal(klog.Format(obj).MarshalLog())")
	}
}

func assertEqual(t *testing.T, expected, actual, what string) {
	if expected != actual {
		t.Errorf("%s:\nExpected\n%s\nActual\n%s\n", what, expected, actual)
	}
}

type TypeMeta struct {
	Kind string
}

func (t TypeMeta) String() string {
	return "kind is " + t.Kind
}

func (t TypeMeta) MarshalLog() interface{} {
	return t.Kind
}

type config struct {
	TypeMeta

	RealField int
}


================================================
FILE: go.mod
================================================
module k8s.io/klog/v2

go 1.21

require github.com/go-logr/logr v1.4.1


================================================
FILE: go.sum
================================================
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=


================================================
FILE: hack/verify-apidiff.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -o errexit
set -o nounset
set -o pipefail

function usage {
  local script="$(basename $0)"

  echo >&2 "Usage: ${script} [-r <branch|tag> | -d <dir>]

This script should be run at the root of a module.

-r <branch|tag>
  Compare the exported API of the local working copy with the 
  exported API of the local repo at the specified branch or tag.

-d <dir>
  Compare the exported API of the local working copy with the 
  exported API of the specified directory, which should point
  to the root of a different version of the same module.

Examples:
  ${script} -r master
  ${script} -r v1.10.0
  ${script} -r release-1.10
  ${script} -d /path/to/historical/version
"
  exit 1
}

ref=""
dir=""
while getopts r:d: o
do case "$o" in
  r)    ref="$OPTARG";;
  d)    dir="$OPTARG";;
  [?])  usage;;
  esac
done

# If REF and DIR are empty, print usage and error
if [[ -z "${ref}" && -z "${dir}" ]]; then
  usage;
fi
# If REF and DIR are both set, print usage and error
if [[ -n "${ref}" && -n "${dir}" ]]; then
  usage;
fi

if ! which apidiff > /dev/null; then
  echo "Installing golang.org/x/exp/cmd/apidiff..."
  pushd "${TMPDIR:-/tmp}" > /dev/null
    GO111MODULE=off go get golang.org/x/exp/cmd/apidiff
  popd > /dev/null
fi

output=$(mktemp -d -t "apidiff.output.XXXX")
cleanup_output () { rm -fr "${output}"; }
trap cleanup_output EXIT

# If ref is set, clone . to temp dir at $ref, and set $dir to the temp dir
clone=""
base="${dir}"
if [[ -n "${ref}" ]]; then
  base="${ref}"
  clone=$(mktemp -d -t "apidiff.clone.XXXX")
  cleanup_clone_and_output () { rm -fr "${clone}"; cleanup_output; }
  trap cleanup_clone_and_output EXIT
  git clone . -q --no-tags -b "${ref}" "${clone}"
  dir="${clone}"
fi

pushd "${dir}" >/dev/null
  echo "Inspecting API of ${base}..."
  go list ./... > packages.txt
  for pkg in $(cat packages.txt); do
    mkdir -p "${output}/${pkg}"
    apidiff -w "${output}/${pkg}/apidiff.output" "${pkg}"
  done
popd >/dev/null

retval=0

echo "Comparing with ${base}..."
for pkg in $(go list ./...); do
  # New packages are ok
  if [ ! -f "${output}/${pkg}/apidiff.output" ]; then
    continue
  fi

  # Check for incompatible changes to previous packages
  incompatible=$(apidiff -incompatible "${output}/${pkg}/apidiff.output" "${pkg}")
  if [[ -n "${incompatible}" ]]; then
    echo >&2 "FAIL: ${pkg} contains incompatible changes:
${incompatible}
"
    retval=1
  fi
done

# Check for removed packages
removed=$(comm -23 "${dir}/packages.txt" <(go list ./...))
if [[ -n "${removed}" ]]; then
  echo >&2 "FAIL: removed packages:
${removed}
"
  retval=1
fi

exit $retval


================================================
FILE: imports.go
================================================
/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package klog

import (
	"github.com/go-logr/logr"
)

// The reason for providing these aliases is to allow code to work with logr
// without directly importing it.

// Logger in this package is exactly the same as logr.Logger.
type Logger = logr.Logger

// LogSink in this package is exactly the same as logr.LogSink.
type LogSink = logr.LogSink

// Runtimeinfo in this package is exactly the same as logr.RuntimeInfo.
type RuntimeInfo = logr.RuntimeInfo

var (
	// New is an alias for logr.New.
	New = logr.New
)


================================================
FILE: integration_tests/internal/main.go
================================================
/*

This file is intended to be used as a standin for a klog'ed executable.

It is called by the integration test via `go run` and with different klog
flags to assert on klog behaviour, especially where klog logs its output
when different combinations of the klog flags are at play.

This file is not intended to be used outside of the integration tests and
is not supposed to be a (good) example on how to use klog.

*/

package main

import (
	"flag"
	"fmt"
	"os"

	"k8s.io/klog/v2"
)

func main() {
	infoLogLine := getEnvOrDie("KLOG_INFO_LOG")
	warningLogLine := getEnvOrDie("KLOG_WARNING_LOG")
	errorLogLine := getEnvOrDie("KLOG_ERROR_LOG")
	fatalLogLine := getEnvOrDie("KLOG_FATAL_LOG")

	klog.InitFlags(nil)
	flag.Parse()
	klog.Info(infoLogLine)
	klog.Warning(warningLogLine)
	klog.Error(errorLogLine)
	klog.Flush()
	klog.Fatal(fatalLogLine)
}

func getEnvOrDie(name string) string {
	val, ok := os.LookupEnv(name)
	if !ok {
		fmt.Fprintln(os.Stderr, name, "could not be found in environment")
		os.Exit(1)
	}
	return val
}


================================================
FILE: integration_tests/klog_test.go
================================================
package integration_tests_test

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"testing"
)

const (
	infoLog    = "this is a info log line"
	warningLog = "this is a warning log line"
	errorLog   = "this is a error log line"
	fatalLog   = "this is a fatal log line"
)

// res is a type alias to a slice of pointers to regular expressions.
type res = []*regexp.Regexp

var (
	infoLogRE    = regexp.MustCompile(regexp.QuoteMeta(infoLog))
	warningLogRE = regexp.MustCompile(regexp.QuoteMeta(warningLog))
	errorLogRE   = regexp.MustCompile(regexp.QuoteMeta(errorLog))
	fatalLogRE   = regexp.MustCompile(regexp.QuoteMeta(fatalLog))

	stackTraceRE = regexp.MustCompile(`\ngoroutine \d+ \[[^]]+\]:\n`)

	allLogREs = res{infoLogRE, warningLogRE, errorLogRE, fatalLogRE, stackTraceRE}

	defaultExpectedInDirREs = map[int]res{
		0: {stackTraceRE, fatalLogRE, errorLogRE, warningLogRE, infoLogRE},
		1: {stackTraceRE, fatalLogRE, errorLogRE, warningLogRE},
		2: {stackTraceRE, fatalLogRE, errorLogRE},
		3: {stackTraceRE, fatalLogRE},
	}
	expectedOneOutputInDirREs = map[int]res{
		0: {infoLogRE},
		1: {warningLogRE},
		2: {errorLogRE},
		3: {fatalLogRE},
	}

	defaultNotExpectedInDirREs = map[int]res{
		0: {},
		1: {infoLogRE},
		2: {infoLogRE, warningLogRE},
		3: {infoLogRE, warningLogRE, errorLogRE},
	}
)

func TestDestinationsWithDifferentFlags(t *testing.T) {
	tests := map[string]struct {
		// logfile states if the flag -log_file should be set
		logfile bool
		// logdir states if the flag -log_dir should be set
		logdir bool
		// flags is for additional flags to pass to the klog'ed executable
		flags []string

		// expectedLogFile states if we generally expect the log file to exist.
		// If this is not set, we expect the file not to exist and will error if it
		// does.
		expectedLogFile bool
		// expectedLogDir states if we generally expect the log files in the log
		// dir to exist.
		// If this is not set, we expect the log files in the log dir not to exist and
		// will error if they do.
		expectedLogDir bool

		// expectedOnStderr is a list of REs we expect to find on stderr
		expectedOnStderr res
		// notExpectedOnStderr is a list of REs that we must not find on stderr
		notExpectedOnStderr res
		// expectedInFile is a list of REs we expect to find in the log file
		expectedInFile res
		// notExpectedInFile is a list of REs we must not find in the log file
		notExpectedInFile res

		// expectedInDir is a list of REs we expect to find in the log files in the
		// log dir, specified by log severity (0 = warning, 1 = info, ...)
		expectedInDir map[int]res
		// notExpectedInDir is a list of REs we must not find in the log files in
		// the log dir, specified by log severity (0 = warning, 1 = info, ...)
		notExpectedInDir map[int]res
	}{
		"default flags": {
			// Everything, EXCEPT the trace on fatal, goes to stderr

			expectedOnStderr:    res{infoLogRE, warningLogRE, errorLogRE, fatalLogRE},
			notExpectedOnStderr: res{stackTraceRE},
		},
		"everything disabled": {
			// Nothing, including the trace on fatal, is showing anywhere

			flags: []string{"-logtostderr=false", "-alsologtostderr=false", "-stderrthreshold=1000"},

			notExpectedOnStderr: allLogREs,
		},
		"everything disabled but low stderrthreshold": {
			// Everything above -stderrthreshold, including the trace on fatal, will
			// be logged to stderr, even if we set -logtostderr to false.

			flags: []string{"-logtostderr=false", "-alsologtostderr=false", "-stderrthreshold=1"},

			expectedOnStderr:    res{warningLogRE, errorLogRE, stackTraceRE},
			notExpectedOnStderr: res{infoLogRE},
		},
		"with logtostderr only": {
			// Everything, EXCEPT the trace on fatal, goes to stderr

			flags: []string{"-logtostderr=true", "-alsologtostderr=false", "-stderrthreshold=1000"},

			expectedOnStderr:    res{infoLogRE, warningLogRE, errorLogRE, fatalLogRE},
			notExpectedOnStderr: res{stackTraceRE},
		},
		"with log file only": {
			// Everything, including the trace on fatal, goes to the single log file

			logfile: true,
			flags:   []string{"-logtostderr=false", "-alsologtostderr=false", "-stderrthreshold=1000"},

			expectedLogFile: true,

			notExpectedOnStderr: allLogREs,
			expectedInFile:      allLogREs,
		},
		"with log dir only": {
			// Everything, including the trace on fatal, goes to the log files in the log dir

			logdir: true,
			flags:  []string{"-logtostderr=false", "-alsologtostderr=false", "-stderrthreshold=1000"},

			expectedLogDir: true,

			notExpectedOnStderr: allLogREs,
			expectedInDir:       defaultExpectedInDirREs,
			notExpectedInDir:    defaultNotExpectedInDirREs,
		},
		"with log dir only and one_output": {
			// Everything, including the trace on fatal, goes to the log files in the log dir

			logdir: true,
			flags:  []string{"-logtostderr=false", "-alsologtostderr=false", "-stderrthreshold=1000", "-one_output=true"},

			expectedLogDir: true,

			notExpectedOnStderr: allLogREs,
			expectedInDir:       expectedOneOutputInDirREs,
			notExpectedInDir:    defaultNotExpectedInDirREs,
		},
		"with log dir and logtostderr": {
			// Everything, EXCEPT the trace on fatal, goes to stderr. The -log_dir is
			// ignored, nothing goes to the log files in the log dir.

			logdir: true,
			flags:  []string{"-logtostderr=true", "-alsologtostderr=false", "-stderrthreshold=1000"},

			expectedOnStderr:    res{infoLogRE, warningLogRE, errorLogRE, fatalLogRE},
			notExpectedOnStderr: res{stackTraceRE},
		},
		"with log file and log dir": {
			// Everything, including the trace on fatal, goes to the single log file.
			// The -log_dir is ignored, nothing goes to the log file in the log dir.

			logdir:  true,
			logfile: true,
			flags:   []string{"-logtostderr=false", "-alsologtostderr=false", "-stderrthreshold=1000"},

			expectedLogFile: true,

			notExpectedOnStderr: allLogREs,
			expectedInFile:      allLogREs,
		},
		"with log file and alsologtostderr": {
			// Everything, including the trace on fatal, goes to the single log file
			// AND to stderr.

			flags:   []string{"-alsologtostderr=true", "-logtostderr=false", "-stderrthreshold=1000"},
			logfile: true,

			expectedLogFile: true,

			expectedOnStderr: allLogREs,
			expectedInFile:   allLogREs,
		},
		"with log dir and alsologtostderr": {
			// Everything, including the trace on fatal, goes to the log file in the
			// log dir AND to stderr.

			logdir: true,
			flags:  []string{"-alsologtostderr=true", "-logtostderr=false", "-stderrthreshold=1000"},

			expectedLogDir: true,

			expectedOnStderr: allLogREs,
			expectedInDir:    defaultExpectedInDirREs,
			notExpectedInDir: defaultNotExpectedInDirREs,
		},
		"with log dir, alsologtostderr and one_output": {
			// Everything, including the trace on fatal, goes to the log file in the
			// log dir AND to stderr.

			logdir: true,
			flags:  []string{"-alsologtostderr=true", "-logtostderr=false", "-stderrthreshold=1000", "-one_output=true"},

			expectedLogDir: true,

			expectedOnStderr: allLogREs,
			expectedInDir:    expectedOneOutputInDirREs,
			notExpectedInDir: defaultNotExpectedInDirREs,
		},
	}

	binaryFileExtention := ""
	if runtime.GOOS == "windows" {
		binaryFileExtention = ".exe"
	}

	for tcName, tc := range tests {
		tc := tc
		t.Run(tcName, func(t *testing.T) {
			t.Parallel()
			withTmpDir(t, func(logdir string) {
				// :: Setup
				flags := tc.flags
				stderr := &bytes.Buffer{}
				logfile := filepath.Join(logdir, "the_single_log_file") // /some/tmp/dir/the_single_log_file

				if tc.logfile {
					flags = append(flags, "-log_file="+logfile)
				}
				if tc.logdir {
					flags = append(flags, "-log_dir="+logdir)
				}

				// :: Execute
				klogRun(t, flags, stderr)

				// :: Assert
				// check stderr
				checkForLogs(t, tc.expectedOnStderr, tc.notExpectedOnStderr, stderr.String(), "stderr")

				// check log_file
				if tc.expectedLogFile {
					content := getFileContent(t, logfile)
					checkForLogs(t, tc.expectedInFile, tc.notExpectedInFile, content, "logfile")
				} else {
					assertFileIsAbsent(t, logfile)
				}

				// check files in log_dir
				for level, levelName := range logFileLevels {
					binaryName := "main" + binaryFileExtention
					logfile, err := getLogFilePath(logdir, binaryName, levelName)
					if tc.expectedLogDir {
						if err != nil {
							t.Errorf("Unable to find log file: %v", err)
						}
						content := getFileContent(t, logfile)
						checkForLogs(t, tc.expectedInDir[level], tc.notExpectedInDir[level], content, "logfile["+logfile+"]")
					} else {
						if err == nil {
							t.Errorf("Unexpectedly found log file %s", logfile)
						}
					}
				}
			})
		})
	}
}

const klogExampleGoFile = "./internal/main.go"

// klogRun spawns a simple executable that uses klog, to later inspect its
// stderr and potentially created log files
func klogRun(t *testing.T, flags []string, stderr io.Writer) {
	callFlags := []string{"run", klogExampleGoFile}
	callFlags = append(callFlags, flags...)

	cmd := exec.Command("go", callFlags...)
	cmd.Stderr = stderr
	cmd.Env = append(os.Environ(),
		"KLOG_INFO_LOG="+infoLog,
		"KLOG_WARNING_LOG="+warningLog,
		"KLOG_ERROR_LOG="+errorLog,
		"KLOG_FATAL_LOG="+fatalLog,
	)

	err := cmd.Run()

	if _, ok := err.(*exec.ExitError); !ok {
		t.Fatalf("Run failed: %v", err)
	}
}

var logFileLevels = map[int]string{
	0: "INFO",
	1: "WARNING",
	2: "ERROR",
	3: "FATAL",
}

func getFileContent(t *testing.T, filePath string) string {
	content, err := ioutil.ReadFile(filePath)
	if err != nil {
		t.Errorf("Could not read file '%s': %v", filePath, err)
	}
	return string(content)
}

func assertFileIsAbsent(t *testing.T, filePath string) {
	if _, err := os.Stat(filePath); !os.IsNotExist(err) {
		t.Errorf("Expected file '%s' not to exist", filePath)
	}
}

func checkForLogs(t *testing.T, expected, disallowed res, content, name string) {
	for _, re := range expected {
		checkExpected(t, true, name, content, re)
	}
	for _, re := range disallowed {
		checkExpected(t, false, name, content, re)
	}
}

func checkExpected(t *testing.T, expected bool, where string, haystack string, needle *regexp.Regexp) {
	found := needle.MatchString(haystack)

	if expected && !found {
		t.Errorf("Expected to find '%s' in %s", needle, where)
	}
	if !expected && found {
		t.Errorf("Expected not to find '%s' in %s", needle, where)
	}
}

func withTmpDir(t *testing.T, f func(string)) {
	tmpDir, err := ioutil.TempDir("", "klog_e2e_")
	if err != nil {
		t.Fatalf("Could not create temp directory: %v", err)
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			t.Fatalf("Could not remove temp directory '%s': %v", tmpDir, err)
		}
	}()

	f(tmpDir)
}

// getLogFileFromDir returns the path of either the symbolic link to the logfile, or the the logfile itself. This must
// be done as the creation of a symlink is not guaranteed on any platform. On Windows, only users with administration
// privileges can create a symlink.
func getLogFilePath(dir, binaryName, levelName string) (string, error) {
	symlink := filepath.Join(dir, binaryName+"."+levelName)
	if _, err := os.Stat(symlink); err == nil {
		return symlink, nil
	}
	files, err := ioutil.ReadDir(dir)
	if err != nil {
		return "", fmt.Errorf("could not read directory %s: %v", dir, err)
	}
	var foundFile string
	for _, file := range files {
		if strings.HasPrefix(file.Name(), binaryName) && strings.Contains(file.Name(), levelName) {
			if foundFile != "" {
				return "", fmt.Errorf("found multiple matching files")
			}
			foundFile = file.Name()
		}
	}
	if foundFile != "" {
		return filepath.Join(dir, foundFile), nil
	}
	return "", fmt.Errorf("file missing from directory")
}


================================================
FILE: internal/buffer/buffer.go
================================================
// Copyright 2013 Google Inc. All Rights Reserved.
// Copyright 2022 The Kubernetes Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package buffer provides a cache for byte.Buffer instances that can be reused
// to avoid frequent allocation and deallocation. It also has utility code
// for log header formatting that use these buffers.
package buffer

import (
	"bytes"
	"os"
	"sync"
	"time"

	"k8s.io/klog/v2/internal/severity"
)

var (
	// Pid is inserted into log headers. Can be overridden for tests.
	Pid = os.Getpid()

	// Time, if set, will be used instead of the actual current time.
	Time *time.Time
)

// Buffer holds a single byte.Buffer for reuse. The zero value is ready for
// use. It also provides some helper methods for output formatting.
type Buffer struct {
	bytes.Buffer
	Tmp [64]byte // temporary byte array for creating headers.
}

var buffers = sync.Pool{
	New: func() interface{} {
		return new(Buffer)
	},
}

// GetBuffer returns a new, ready-to-use buffer.
func GetBuffer() *Buffer {
	b := buffers.Get().(*Buffer)
	b.Reset()
	return b
}

// PutBuffer returns a buffer to the free list.
func PutBuffer(b *Buffer) {
	if b.Len() >= 256 {
		// Let big buffers die a natural death, without relying on
		// sync.Pool behavior. The documentation implies that items may
		// get deallocated while stored there ("If the Pool holds the
		// only reference when this [= be removed automatically]
		// happens, the item might be deallocated."), but
		// https://github.com/golang/go/issues/23199 leans more towards
		// having such a size limit.
		return
	}

	buffers.Put(b)
}

// Some custom tiny helper functions to print the log header efficiently.

const digits = "0123456789"

// twoDigits formats a zero-prefixed two-digit integer at buf.Tmp[i].
func (buf *Buffer) twoDigits(i, d int) {
	buf.Tmp[i+1] = digits[d%10]
	d /= 10
	buf.Tmp[i] = digits[d%10]
}

// nDigits formats an n-digit integer at buf.Tmp[i],
// padding with pad on the left.
// It assumes d >= 0.
func (buf *Buffer) nDigits(n, i, d int, pad byte) {
	j := n - 1
	for ; j >= 0 && d > 0; j-- {
		buf.Tmp[i+j] = digits[d%10]
		d /= 10
	}
	for ; j >= 0; j-- {
		buf.Tmp[i+j] = pad
	}
}

// someDigits formats a zero-prefixed variable-width integer at buf.Tmp[i].
func (buf *Buffer) someDigits(i, d int) int {
	// Print into the top, then copy down. We know there's space for at least
	// a 10-digit number.
	j := len(buf.Tmp)
	for {
		j--
		buf.Tmp[j] = digits[d%10]
		d /= 10
		if d == 0 {
			break
		}
	}
	return copy(buf.Tmp[i:], buf.Tmp[j:])
}

// FormatHeader formats a log header using the provided file name and line number
// and writes it into the buffer.
func (buf *Buffer) FormatHeader(s severity.Severity, file string, line int, now time.Time) {
	if line < 0 {
		line = 0 // not a real line number, but acceptable to someDigits
	}
	if s > severity.FatalLog {
		s = severity.InfoLog // for safety.
	}

	// Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand.
	// It's worth about 3X. Fprintf is hard.
	if Time != nil {
		now = *Time
	}
	_, month, day := now.Date()
	hour, minute, second := now.Clock()
	// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
	buf.Tmp[0] = severity.Char[s]
	buf.twoDigits(1, int(month))
	buf.twoDigits(3, day)
	buf.Tmp[5] = ' '
	buf.twoDigits(6, hour)
	buf.Tmp[8] = ':'
	buf.twoDigits(9, minute)
	buf.Tmp[11] = ':'
	buf.twoDigits(12, second)
	buf.Tmp[14] = '.'
	buf.nDigits(6, 15, now.Nanosecond()/1000, '0')
	buf.Tmp[21] = ' '
	buf.nDigits(7, 22, Pid, ' ') // TODO: should be TID
	buf.Tmp[29] = ' '
	buf.Write(buf.Tmp[:30])
	buf.WriteString(file)
	buf.Tmp[0] = ':'
	n := buf.someDigits(1, line)
	buf.Tmp[n+1] = ']'
	buf.Tmp[n+2] = ' '
	buf.Write(buf.Tmp[:n+3])
}

// SprintHeader formats a log header and returns a string. This is a simpler
// version of FormatHeader for use in ktesting.
func (buf *Buffer) SprintHeader(s severity.Severity, now time.Time) string {
	if s > severity.FatalLog {
		s = severity.InfoLog // for safety.
	}

	// Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand.
	// It's worth about 3X. Fprintf is hard.
	if Time != nil {
		now = *Time
	}
	_, month, day := now.Date()
	hour, minute, second := now.Clock()
	// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
	buf.Tmp[0] = severity.Char[s]
	buf.twoDigits(1, int(month))
	buf.twoDigits(3, day)
	buf.Tmp[5] = ' '
	buf.twoDigits(6, hour)
	buf.Tmp[8] = ':'
	buf.twoDigits(9, minute)
	buf.Tmp[11] = ':'
	buf.twoDigits(12, second)
	buf.Tmp[14] = '.'
	buf.nDigits(6, 15, now.Nanosecond()/1000, '0')
	buf.Tmp[21] = ']'
	return string(buf.Tmp[:22])
}


================================================
FILE: internal/clock/README.md
================================================
# Clock

This package provides an interface for time-based operations.  It allows
mocking time for testing.

This is a copy of k8s.io/utils/clock. We have to copy it to avoid a circular
dependency (k8s.io/klog -> k8s.io/utils -> k8s.io/klog).


================================================
FILE: internal/clock/clock.go
================================================
/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package clock

import "time"

// PassiveClock allows for injecting fake or real clocks into code
// that needs to read the current time but does not support scheduling
// activity in the future.
type PassiveClock interface {
	Now() time.Time
	Since(time.Time) time.Duration
}

// Clock allows for injecting fake or real clocks into code that
// needs to do arbitrary things based on time.
type Clock interface {
	PassiveClock
	// After returns the channel of a new Timer.
	// This method does not allow to free/GC the backing timer before it fires. Use
	// NewTimer instead.
	After(d time.Duration) <-chan time.Time
	// NewTimer returns a new Timer.
	NewTimer(d time.Duration) Timer
	// Sleep sleeps for the provided duration d.
	// Consider making the sleep interruptible by using 'select' on a context channel and a timer channel.
	Sleep(d time.Duration)
	// NewTicker returns a new Ticker.
	NewTicker(time.Duration) Ticker
}

// WithDelayedExecution allows for injecting fake or real clocks into
// code that needs to make use of AfterFunc functionality.
type WithDelayedExecution interface {
	Clock
	// AfterFunc executes f in its own goroutine after waiting
	// for d duration and returns a Timer whose channel can be
	// closed by calling Stop() on the Timer.
	AfterFunc(d time.Duration, f func()) Timer
}

// WithTickerAndDelayedExecution allows for injecting fake or real clocks
// into code that needs Ticker and AfterFunc functionality
type WithTickerAndDelayedExecution interface {
	Clock
	// AfterFunc executes f in its own goroutine after waiting
	// for d duration and returns a Timer whose channel can be
	// closed by calling Stop() on the Timer.
	AfterFunc(d time.Duration, f func()) Timer
}

// Ticker defines the Ticker interface.
type Ticker interface {
	C() <-chan time.Time
	Stop()
}

var _ Clock = RealClock{}

// RealClock really calls time.Now()
type RealClock struct{}

// Now returns the current time.
func (RealClock) Now() time.Time {
	return time.Now()
}

// Since returns time since the specified timestamp.
func (RealClock) Since(ts time.Time) time.Duration {
	return time.Since(ts)
}

// After is the same as time.After(d).
// This method does not allow to free/GC the backing timer before it fires. Use
// NewTimer instead.
func (RealClock) After(d time.Duration) <-chan time.Time {
	return time.After(d)
}

// NewTimer is the same as time.NewTimer(d)
func (RealClock) NewTimer(d time.Duration) Timer {
	return &realTimer{
		timer: time.NewTimer(d),
	}
}

// AfterFunc is the same as time.AfterFunc(d, f).
func (RealClock) AfterFunc(d time.Duration, f func()) Timer {
	return &realTimer{
		timer: time.AfterFunc(d, f),
	}
}

// NewTicker returns a new Ticker.
func (RealClock) NewTicker(d time.Duration) Ticker {
	return &realTicker{
		ticker: time.NewTicker(d),
	}
}

// Sleep is the same as time.Sleep(d)
// Consider making the sleep interruptible by using 'select' on a context channel and a timer channel.
func (RealClock) Sleep(d time.Duration) {
	time.Sleep(d)
}

// Timer allows for injecting fake or real timers into code that
// needs to do arbitrary things based on time.
type Timer interface {
	C() <-chan time.Time
	Stop() bool
	Reset(d time.Duration) bool
}

var _ = Timer(&realTimer{})

// realTimer is backed by an actual time.Timer.
type realTimer struct {
	timer *time.Timer
}

// C returns the underlying timer's channel.
func (r *realTimer) C() <-chan time.Time {
	return r.timer.C
}

// Stop calls Stop() on the underlying timer.
func (r *realTimer) Stop() bool {
	return r.timer.Stop()
}

// Reset calls Reset() on the underlying timer.
func (r *realTimer) Reset(d time.Duration) bool {
	return r.timer.Reset(d)
}

type realTicker struct {
	ticker *time.Ticker
}

func (r *realTicker) C() <-chan time.Time {
	return r.ticker.C
}

func (r *realTicker) Stop() {
	r.ticker.Stop()
}


================================================
FILE: internal/clock/testing/fake_clock.go
================================================
/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package testing

import (
	"sync"
	"time"

	"k8s.io/klog/v2/internal/clock"
)

var (
	_ = clock.PassiveClock(&FakePassiveClock{})
	_ = clock.Clock(&IntervalClock{})
)

// FakePassiveClock implements PassiveClock, but returns an arbitrary time.
type FakePassiveClock struct {
	lock sync.RWMutex
	time time.Time
}

// FakeClock implements clock.Clock, but returns an arbitrary time.
type FakeClock struct {
	FakePassiveClock

	// waiters are waiting for the fake time to pass their specified time
	waiters []*fakeClockWaiter
}

type fakeClockWaiter struct {
	targetTime    time.Time
	stepInterval  time.Duration
	skipIfBlocked bool
	destChan      chan time.Time
	fired         bool
	afterFunc     func()
}

// NewFakePassiveClock returns a new FakePassiveClock.
func NewFakePassiveClock(t time.Time) *FakePassiveClock {
	return &FakePassiveClock{
		time: t,
	}
}

// NewFakeClock constructs a fake clock set to the provided time.
func NewFakeClock(t time.Time) *FakeClock {
	return &FakeClock{
		FakePassiveClock: *NewFakePassiveClock(t),
	}
}

// Now returns f's time.
func (f *FakePassiveClock) Now() time.Time {
	f.lock.RLock()
	defer f.lock.RUnlock()
	return f.time
}

// Since returns time since the time in f.
func (f *FakePassiveClock) Since(ts time.Time) time.Duration {
	f.lock.RLock()
	defer f.lock.RUnlock()
	return f.time.Sub(ts)
}

// SetTime sets the time on the FakePassiveClock.
func (f *FakePassiveClock) SetTime(t time.Time) {
	f.lock.Lock()
	defer f.lock.Unlock()
	f.time = t
}

// After is the fake version of time.After(d).
func (f *FakeClock) After(d time.Duration) <-chan time.Time {
	f.lock.Lock()
	defer f.lock.Unlock()
	stopTime := f.time.Add(d)
	ch := make(chan time.Time, 1) // Don't block!
	f.waiters = append(f.waiters, &fakeClockWaiter{
		targetTime: stopTime,
		destChan:   ch,
	})
	return ch
}

// NewTimer constructs a fake timer, akin to time.NewTimer(d).
func (f *FakeClock) NewTimer(d time.Duration) clock.Timer {
	f.lock.Lock()
	defer f.lock.Unlock()
	stopTime := f.time.Add(d)
	ch := make(chan time.Time, 1) // Don't block!
	timer := &fakeTimer{
		fakeClock: f,
		waiter: fakeClockWaiter{
			targetTime: stopTime,
			destChan:   ch,
		},
	}
	f.waiters = append(f.waiters, &timer.waiter)
	return timer
}

// AfterFunc is the Fake version of time.AfterFunc(d, cb).
func (f *FakeClock) AfterFunc(d time.Duration, cb func()) clock.Timer {
	f.lock.Lock()
	defer f.lock.Unlock()
	stopTime := f.time.Add(d)
	ch := make(chan time.Time, 1) // Don't block!

	timer := &fakeTimer{
		fakeClock: f,
		waiter: fakeClockWaiter{
			targetTime: stopTime,
			destChan:   ch,
			afterFunc:  cb,
		},
	}
	f.waiters = append(f.waiters, &timer.waiter)
	return timer
}

// Tick constructs a fake ticker, akin to time.Tick
func (f *FakeClock) Tick(d time.Duration) <-chan time.Time {
	if d <= 0 {
		return nil
	}
	f.lock.Lock()
	defer f.lock.Unlock()
	tickTime := f.time.Add(d)
	ch := make(chan time.Time, 1) // hold one tick
	f.waiters = append(f.waiters, &fakeClockWaiter{
		targetTime:    tickTime,
		stepInterval:  d,
		skipIfBlocked: true,
		destChan:      ch,
	})

	return ch
}

// NewTicker returns a new Ticker.
func (f *FakeClock) NewTicker(d time.Duration) clock.Ticker {
	f.lock.Lock()
	defer f.lock.Unlock()
	tickTime := f.time.Add(d)
	ch := make(chan time.Time, 1) // hold one tick
	f.waiters = append(f.waiters, &fakeClockWaiter{
		targetTime:    tickTime,
		stepInterval:  d,
		skipIfBlocked: true,
		destChan:      ch,
	})

	return &fakeTicker{
		c: ch,
	}
}

// Step moves the clock by Duration and notifies anyone that's called After,
// Tick, or NewTimer.
func (f *FakeClock) Step(d time.Duration) {
	f.lock.Lock()
	defer f.lock.Unlock()
	f.setTimeLocked(f.time.Add(d))
}

// SetTime sets the time.
func (f *FakeClock) SetTime(t time.Time) {
	f.lock.Lock()
	defer f.lock.Unlock()
	f.setTimeLocked(t)
}

// Actually changes the time and checks any waiters. f must be write-locked.
func (f *FakeClock) setTimeLocked(t time.Time) {
	f.time = t
	newWaiters := make([]*fakeClockWaiter, 0, len(f.waiters))
	for i := range f.waiters {
		w := f.waiters[i]
		if !w.targetTime.After(t) {
			if w.skipIfBlocked {
				select {
				case w.destChan <- t:
					w.fired = true
				default:
				}
			} else {
				w.destChan <- t
				w.fired = true
			}

			if w.afterFunc != nil {
				w.afterFunc()
			}

			if w.stepInterval > 0 {
				for !w.targetTime.After(t) {
					w.targetTime = w.targetTime.Add(w.stepInterval)
				}
				newWaiters = append(newWaiters, w)
			}

		} else {
			newWaiters = append(newWaiters, f.waiters[i])
		}
	}
	f.waiters = newWaiters
}

// HasWaiters returns true if After or AfterFunc has been called on f but not yet satisfied (so you can
// write race-free tests).
func (f *FakeClock) HasWaiters() bool {
	f.lock.RLock()
	defer f.lock.RUnlock()
	return len(f.waiters) > 0
}

// Sleep is akin to time.Sleep
func (f *FakeClock) Sleep(d time.Duration) {
	f.Step(d)
}

// IntervalClock implements clock.PassiveClock, but each invocation of Now steps the clock forward the specified duration.
// IntervalClock technically implements the other methods of clock.Clock, but each implementation is just a panic.
//
// Deprecated: See SimpleIntervalClock for an alternative that only has the methods of PassiveClock.
type IntervalClock struct {
	Time     time.Time
	Duration time.Duration
}

// Now returns i's time.
func (i *IntervalClock) Now() time.Time {
	i.Time = i.Time.Add(i.Duration)
	return i.Time
}

// Since returns time since the time in i.
func (i *IntervalClock) Since(ts time.Time) time.Duration {
	return i.Time.Sub(ts)
}

// After is unimplemented, will panic.
// TODO: make interval clock use FakeClock so this can be implemented.
func (*IntervalClock) After(time.Duration) <-chan time.Time {
	panic("IntervalClock doesn't implement After")
}

// NewTimer is unimplemented, will panic.
// TODO: make interval clock use FakeClock so this can be implemented.
func (*IntervalClock) NewTimer(time.Duration) clock.Timer {
	panic("IntervalClock doesn't implement NewTimer")
}

// AfterFunc is unimplemented, will panic.
// TODO: make interval clock use FakeClock so this can be implemented.
func (*IntervalClock) AfterFunc(time.Duration, func()) clock.Timer {
	panic("IntervalClock doesn't implement AfterFunc")
}

// NewTicker has no implementation yet and is omitted.
// TODO: make interval clock use FakeClock so this can be implemented.
func (*IntervalClock) NewTicker(time.Duration) clock.Ticker {
	panic("IntervalClock doesn't implement NewTicker")
}

// Sleep is unimplemented, will panic.
func (*IntervalClock) Sleep(time.Duration) {
	panic("IntervalClock doesn't implement Sleep")
}

var _ = clock.Timer(&fakeTimer{})

// fakeTimer implements clock.Timer based on a FakeClock.
type fakeTimer struct {
	fakeClock *FakeClock
	waiter    fakeClockWaiter
}

// C returns the channel that notifies when this timer has fired.
func (f *fakeTimer) C() <-chan time.Time {
	return f.waiter.destChan
}

// Stop stops the timer and returns true if the timer has not yet fired, or false otherwise.
func (f *fakeTimer) Stop() bool {
	f.fakeClock.lock.Lock()
	defer f.fakeClock.lock.Unlock()

	newWaiters := make([]*fakeClockWaiter, 0, len(f.fakeClock.waiters))
	for i := range f.fakeClock.waiters {
		w := f.fakeClock.waiters[i]
		if w != &f.waiter {
			newWaiters = append(newWaiters, w)
		}
	}

	f.fakeClock.waiters = newWaiters

	return !f.waiter.fired
}

// Reset resets the timer to the fake clock's "now" + d. It returns true if the timer has not yet
// fired, or false otherwise.
func (f *fakeTimer) Reset(d time.Duration) bool {
	f.fakeClock.lock.Lock()
	defer f.fakeClock.lock.Unlock()

	active := !f.waiter.fired

	f.waiter.fired = false
	f.waiter.targetTime = f.fakeClock.time.Add(d)

	var isWaiting bool
	for i := range f.fakeClock.waiters {
		w := f.fakeClock.waiters[i]
		if w == &f.waiter {
			isWaiting = true
			break
		}
	}
	if !isWaiting {
		f.fakeClock.waiters = append(f.fakeClock.waiters, &f.waiter)
	}

	return active
}

type fakeTicker struct {
	c <-chan time.Time
}

func (t *fakeTicker) C() <-chan time.Time {
	return t.c
}

func (t *fakeTicker) Stop() {
}


================================================
FILE: internal/clock/testing/simple_interval_clock.go
================================================
/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package testing

import (
	"time"

	"k8s.io/klog/v2/internal/clock"
)

var (
	_ = clock.PassiveClock(&SimpleIntervalClock{})
)

// SimpleIntervalClock implements clock.PassiveClock, but each invocation of Now steps the clock forward the specified duration
type SimpleIntervalClock struct {
	Time     time.Time
	Duration time.Duration
}

// Now returns i's time.
func (i *SimpleIntervalClock) Now() time.Time {
	i.Time = i.Time.Add(i.Duration)
	return i.Time
}

// Since returns time since the time in i.
func (i *SimpleIntervalClock) Since(ts time.Time) time.Duration {
	return i.Time.Sub(ts)
}


================================================
FILE: internal/dbg/dbg.go
================================================
// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
//
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package dbg provides some helper code for call traces.
package dbg

import (
	"runtime"
)

// Stacks is a wrapper for runtime.Stack that attempts to recover the data for
// all goroutines or the calling one.
func Stacks(all bool) []byte {
	// We don't know how big the traces are, so grow a few times if they don't fit. Start large, though.
	n := 10000
	if all {
		n = 100000
	}
	var trace []byte
	for i := 0; i < 5; i++ {
		trace = make([]byte, n)
		nbytes := runtime.Stack(trace, all)
		if nbytes < len(trace) {
			return trace[:nbytes]
		}
		n *= 2
	}
	return trace
}


================================================
FILE: internal/serialize/keyvalues.go
================================================
/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package serialize

import (
	"bytes"
	"encoding/json"
	"fmt"
	"slices"
	"strconv"
	"strings"

	"github.com/go-logr/logr"
)

type textWriter interface {
	WriteText(*bytes.Buffer)
}

// WithValues implements LogSink.WithValues. The old key/value pairs are
// assumed to be well-formed, the new ones are checked and padded if
// necessary. It returns a new slice.
func WithValues(oldKV, newKV []interface{}) []interface{} {
	if len(newKV) == 0 {
		return oldKV
	}
	newLen := len(oldKV) + len(newKV)
	hasMissingValue := newLen%2 != 0
	if hasMissingValue {
		newLen++
	}
	// The new LogSink must have its own slice.
	kv := make([]interface{}, 0, newLen)
	kv = append(kv, oldKV...)
	kv = append(kv, newKV...)
	if hasMissingValue {
		kv = append(kv, missingValue)
	}
	return kv
}

type Formatter struct {
	AnyToStringHook AnyToStringFunc
}

type AnyToStringFunc func(v interface{}) string

const missingValue = "(MISSING)"

func FormatKVs(b *bytes.Buffer, kvs ...[]interface{}) {
	Formatter{}.FormatKVs(b, kvs...)
}

// FormatKVs formats all key/value pairs such that the output contains no
// duplicates ("last one wins").
func (f Formatter) FormatKVs(b *bytes.Buffer, kvs ...[]interface{}) {
	// De-duplication is done by optimistically formatting all key value
	// pairs and then cutting out the output of those key/value pairs which
	// got overwritten later.
	//
	// In the common case of no duplicates, the only overhead is tracking
	// previous keys. This uses a slice with a simple linear search because
	// the number of entries is typically so low that allocating a map or
	// keeping a sorted slice with binary search aren't justified.
	//
	// Using a fixed size here makes the Go compiler use the stack as
	// initial backing store for the slice, which is crucial for
	// performance.
	existing := make([]obsoleteKV, 0, 32)
	obsolete := make([]interval, 0, 32) // Sorted by start index.
	for _, keysAndValues := range kvs {
		for i := 0; i < len(keysAndValues); i += 2 {
			var v interface{}
			k := keysAndValues[i]
			if i+1 < len(keysAndValues) {
				v = keysAndValues[i+1]
			} else {
				v = missingValue
			}
			var e obsoleteKV
			e.start = b.Len()
			e.key = f.KVFormat(b, k, v)
			e.end = b.Len()
			i := findObsoleteEntry(existing, e.key)
			if i >= 0 {
				data := b.Bytes()
				if bytes.Compare(data[existing[i].start:existing[i].end], data[e.start:e.end]) == 0 {
					// The new entry gets obsoleted because it's identical.
					// This has the advantage that key/value pairs from
					// a WithValues call always come first, even if the same
					// pair gets added again later. This makes different log
					// entries more consistent.
					//
					// The new entry has a higher start index and thus can be appended.
					obsolete = append(obsolete, e.interval)
				} else {
					// The old entry gets obsoleted because it's value is different.
					//
					// Sort order is not guaranteed, we have to insert at the right place.
					index, _ := slices.BinarySearchFunc(obsolete, existing[i].interval, func(a, b interval) int { return a.start - b.start })
					obsolete = slices.Insert(obsolete, index, existing[i].interval)
					existing[i].interval = e.interval
				}
			} else {
				// Instead of appending at the end and doing a
				// linear search in findEntry, we could keep
				// the slice sorted by key and do a binary search.
				//
				// Above:
				//    i, ok := slices.BinarySearchFunc(existing, e, func(a, b entry) int { return strings.Compare(a.key, b.key) })
				// Here:
				//    existing = slices.Insert(existing, i, e)
				//
				// But that adds a dependency on the slices package
				// and made performance slightly worse, presumably
				// because the cost of shifting entries around
				// did not pay of with faster lookups.
				existing = append(existing, e)
			}
		}
	}

	// If we need to remove some obsolete key/value pairs then move the memory.
	if len(obsolete) > 0 {
		// Potentially the next remaining output (might itself be obsolete).
		from := obsolete[0].end
		// Next obsolete entry.
		nextObsolete := 1
		// This is the source buffer, before truncation.
		all := b.Bytes()
		b.Truncate(obsolete[0].start)

		for nextObsolete < len(obsolete) {
			if from == obsolete[nextObsolete].start {
				// Skip also the next obsolete key/value.
				from = obsolete[nextObsolete].end
				nextObsolete++
				continue
			}

			// Preserve some output. Write uses copy, which
			// explicitly allows source and destination to overlap.
			// That could happen here.
			valid := all[from:obsolete[nextObsolete].start]
			b.Write(valid)
			from = obsolete[nextObsolete].end
			nextObsolete++
		}
		// Copy end of buffer.
		valid := all[from:]
		b.Write(valid)
	}
}

type obsoleteKV struct {
	key string
	interval
}

// interval includes the start and excludes the end.
type interval struct {
	start int
	end   int
}

func findObsoleteEntry(entries []obsoleteKV, key string) int {
	for i, entry := range entries {
		if entry.key == key {
			return i
		}
	}
	return -1
}

// formatAny is the fallback formatter for a value. It supports a hook (for
// example, for YAML encoding) and itself uses JSON encoding.
func (f Formatter) formatAny(b *bytes.Buffer, v interface{}) {
	if f.AnyToStringHook != nil {
		str := f.AnyToStringHook(v)
		if strings.Contains(str, "\n") {
			// If it's multi-line, then pass it through writeStringValue to get start/end delimiters,
			// which separates it better from any following key/value pair.
			writeStringValue(b, str)
			return
		}
		// Otherwise put it directly after the separator, on the same lime,
		// The assumption is that the hook returns something where start/end are obvious.
		b.WriteRune('=')
		b.WriteString(str)
		return
	}
	b.WriteRune('=')
	formatAsJSON(b, v)
}

func formatAsJSON(b *bytes.Buffer, v interface{}) {
	encoder := json.NewEncoder(b)
	l := b.Len()
	if err := encoder.Encode(v); err != nil {
		// This shouldn't happen. We discard whatever the encoder
		// wrote and instead dump an error string.
		b.Truncate(l)
		b.WriteString(fmt.Sprintf(`"<internal error: %v>"`, err))
		return
	}
	// Remove trailing newline.
	b.Truncate(b.Len() - 1)
}

// StringerToString converts a Stringer to a string,
// handling panics if they occur.
func StringerToString(s fmt.Stringer) (ret string) {
	defer func() {
		if err := recover(); err != nil {
			ret = fmt.Sprintf("<panic: %s>", err)
		}
	}()
	ret = s.String()
	return
}

// MarshalerToValue invokes a marshaler and catches
// panics.
func MarshalerToValue(m logr.Marshaler) (ret interface{}) {
	defer func() {
		if err := recover(); err != nil {
			ret = fmt.Sprintf("<panic: %s>", err)
		}
	}()
	ret = m.MarshalLog()
	return
}

// ErrorToString converts an error to a string,
// handling panics if they occur.
func ErrorToString(err error) (ret string) {
	defer func() {
		if err := recover(); err != nil {
			ret = fmt.Sprintf("<panic: %s>", err)
		}
	}()
	ret = err.Error()
	return
}

func writeTextWriterValue(b *bytes.Buffer, v textWriter) {
	b.WriteByte('=')
	defer func() {
		if err := recover(); err != nil {
			fmt.Fprintf(b, `"<panic: %s>"`, err)
		}
	}()
	v.WriteText(b)
}

func writeStringValue(b *bytes.Buffer, v string) {
	data := []byte(v)
	index := bytes.IndexByte(data, '\n')
	if index == -1 {
		b.WriteByte('=')
		// Simple string, quote quotation marks and non-printable characters.
		b.WriteString(strconv.Quote(v))
		return
	}

	// Complex multi-line string, show as-is with indention like this:
	// I... "hello world" key=<
	// <tab>line 1
	// <tab>line 2
	//  >
	//
	// Tabs indent the lines of the value while the end of string delimiter
	// is indented with a space. That has two purposes:
	// - visual difference between the two for a human reader because indention
	//   will be different
	// - no ambiguity when some value line starts with the end delimiter
	//
	// One downside is that the output cannot distinguish between strings that
	// end with a line break and those that don't because the end delimiter
	// will always be on the next line.
	b.WriteString("=<\n")
	for index != -1 {
		b.WriteByte('\t')
		b.Write(data[0 : index+1])
		data = data[index+1:]
		index = bytes.IndexByte(data, '\n')
	}
	if len(data) == 0 {
		// String ended with line break, don't add another.
		b.WriteString(" >")
	} else {
		// No line break at end of last line, write rest of string and
		// add one.
		b.WriteByte('\t')
		b.Write(data)
		b.WriteString("\n >")
	}
}


================================================
FILE: internal/serialize/keyvalues_no_slog.go
================================================
//go:build !go1.21
// +build !go1.21

/*
Copyright 2023 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package serialize

import (
	"bytes"
	"fmt"

	"github.com/go-logr/logr"
)

// KVFormat serializes one key/value pair into the provided buffer.
// A space gets inserted before the pair.
func (f Formatter) KVFormat(b *bytes.Buffer, k, v interface{}) string {
	// This is the version without slog support. Must be kept in sync with
	// the version in keyvalues_slog.go.

	b.WriteByte(' ')
	// Keys are assumed to be well-formed according to
	// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments
	// for the sake of performance. Keys with spaces,
	// special characters, etc. will break parsing.
	var key string
	if sK, ok := k.(string); ok {
		// Avoid one allocation when the key is a string, which
		// normally it should be.
		key = sK
	} else {
		key = fmt.Sprintf("%s", k)
	}
	b.WriteString(key)

	// The type checks are sorted so that more frequently used ones
	// come first because that is then faster in the common
	// cases. In Kubernetes, ObjectRef (a Stringer) is more common
	// than plain strings
	// (https://github.com/kubernetes/kubernetes/pull/106594#issuecomment-975526235).
	switch v := v.(type) {
	case textWriter:
		writeTextWriterValue(b, v)
	case fmt.Stringer:
		writeStringValue(b, StringerToString(v))
	case string:
		writeStringValue(b, v)
	case error:
		writeStringValue(b, ErrorToString(v))
	case logr.Marshaler:
		value := MarshalerToValue(v)
		// A marshaler that returns a string is useful for
		// delayed formatting of complex values. We treat this
		// case like a normal string. This is useful for
		// multi-line support.
		//
		// We could do this by recursively formatting a value,
		// but that comes with the risk of infinite recursion
		// if a marshaler returns itself. Instead we call it
		// only once and rely on it returning the intended
		// value directly.
		switch value := value.(type) {
		case string:
			writeStringValue(b, value)
		default:
			f.formatAny(b, value)
		}
	case []byte:
		// In https://github.com/kubernetes/klog/pull/237 it was decided
		// to format byte slices with "%+q". The advantages of that are:
		// - readable output if the bytes happen to be printable
		// - non-printable bytes get represented as unicode escape
		//   sequences (\uxxxx)
		//
		// The downsides are that we cannot use the faster
		// strconv.Quote here and that multi-line output is not
		// supported. If developers know that a byte array is
		// printable and they want multi-line output, they can
		// convert the value to string before logging it.
		b.WriteByte('=')
		b.WriteString(fmt.Sprintf("%+q", v))
	default:
		f.formatAny(b, v)
	}

	return key
}


================================================
FILE: internal/serialize/keyvalues_slog.go
================================================
//go:build go1.21
// +build go1.21

/*
Copyright 2023 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package serialize

import (
	"bytes"
	"fmt"
	"log/slog"
	"strconv"

	"github.com/go-logr/logr"
)

// KVFormat serializes one key/value pair into the provided buffer.
// A space gets inserted before the pair. It returns the key.
func (f Formatter) KVFormat(b *bytes.Buffer, k, v interface{}) string {
	// This is the version without slog support. Must be kept in sync with
	// the version in keyvalues_slog.go.

	b.WriteByte(' ')
	// Keys are assumed to be well-formed according to
	// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments
	// for the sake of performance. Keys with spaces,
	// special characters, etc. will break parsing.
	var key string
	if sK, ok := k.(string); ok {
		// Avoid one allocation when the key is a string, which
		// normally it should be.
		key = sK
	} else {
		key = fmt.Sprintf("%s", k)
	}
	b.WriteString(key)

	// The type checks are sorted so that more frequently used ones
	// come first because that is then faster in the common
	// cases. In Kubernetes, ObjectRef (a Stringer) is more common
	// than plain strings
	// (https://github.com/kubernetes/kubernetes/pull/106594#issuecomment-975526235).
	//
	// slog.LogValuer does not need to be handled here because the handler will
	// already have resolved such special values to the final value for logging.
	switch v := v.(type) {
	case textWriter:
		writeTextWriterValue(b, v)
	case slog.Value:
		// This must come before fmt.Stringer because slog.Value implements
		// fmt.Stringer, but does not produce the output that we want.
		b.WriteByte('=')
		generateJSON(b, v)
	case fmt.Stringer:
		writeStringValue(b, StringerToString(v))
	case string:
		writeStringValue(b, v)
	case error:
		writeStringValue(b, ErrorToString(v))
	case logr.Marshaler:
		value := MarshalerToValue(v)
		// A marshaler that returns a string is useful for
		// delayed formatting of complex values. We treat this
		// case like a normal string. This is useful for
		// multi-line support.
		//
		// We could do this by recursively formatting a value,
		// but that comes with the risk of infinite recursion
		// if a marshaler returns itself. Instead we call it
		// only once and rely on it returning the intended
		// value directly.
		switch value := value.(type) {
		case string:
			writeStringValue(b, value)
		default:
			f.formatAny(b, value)
		}
	case slog.LogValuer:
		value := slog.AnyValue(v).Resolve()
		if value.Kind() == slog.KindString {
			writeStringValue(b, value.String())
		} else {
			b.WriteByte('=')
			generateJSON(b, value)
		}
	case []byte:
		// In https://github.com/kubernetes/klog/pull/237 it was decided
		// to format byte slices with "%+q". The advantages of that are:
		// - readable output if the bytes happen to be printable
		// - non-printable bytes get represented as unicode escape
		//   sequences (\uxxxx)
		//
		// The downsides are that we cannot use the faster
		// strconv.Quote here and that multi-line output is not
		// supported. If developers know that a byte array is
		// printable and they want multi-line output, they can
		// convert the value to string before logging it.
		b.WriteByte('=')
		b.WriteString(fmt.Sprintf("%+q", v))
	default:
		f.formatAny(b, v)
	}

	return key
}

// generateJSON has the same preference for plain strings as KVFormat.
// In contrast to KVFormat it always produces valid JSON with no line breaks.
func generateJSON(b *bytes.Buffer, v interface{}) {
	switch v := v.(type) {
	case slog.Value:
		switch v.Kind() {
		case slog.KindGroup:
			// Format as a JSON group. We must not involve f.AnyToStringHook (if there is any),
			// because there is no guarantee that it produces valid JSON.
			b.WriteByte('{')
			for i, attr := range v.Group() {
				if i > 0 {
					b.WriteByte(',')
				}
				b.WriteString(strconv.Quote(attr.Key))
				b.WriteByte(':')
				generateJSON(b, attr.Value)
			}
			b.WriteByte('}')
		case slog.KindLogValuer:
			generateJSON(b, v.Resolve())
		default:
			// Peel off the slog.Value wrapper and format the actual value.
			generateJSON(b, v.Any())
		}
	case fmt.Stringer:
		b.WriteString(strconv.Quote(StringerToString(v)))
	case logr.Marshaler:
		generateJSON(b, MarshalerToValue(v))
	case slog.LogValuer:
		generateJSON(b, slog.AnyValue(v).Resolve().Any())
	case string:
		b.WriteString(strconv.Quote(v))
	case error:
		b.WriteString(strconv.Quote(v.Error()))
	default:
		formatAsJSON(b, v)
	}
}


================================================
FILE: internal/serialize/keyvalues_test.go
================================================
/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package serialize_test

import (
	"bytes"
	"fmt"
	"testing"
	"time"

	"k8s.io/klog/v2"
	"k8s.io/klog/v2/internal/serialize"
	"k8s.io/klog/v2/internal/test"
)

// point conforms to fmt.Stringer interface as it implements the String() method
type point struct {
	x int
	y int
}

// we now have a value receiver
func (p point) String() string {
	return fmt.Sprintf("x=%d, y=%d", p.x, p.y)
}

type dummyStruct struct {
	key   string
	value string
}

func (d *dummyStruct) MarshalLog() interface{} {
	return map[string]string{
		"key-data":   d.key,
		"value-data": d.value,
	}
}

type dummyStructWithStringMarshal struct {
	key   string
	value string
}

func (d *dummyStructWithStringMarshal) MarshalLog() interface{} {
	return fmt.Sprintf("%s=%s", d.key, d.value)
}

// Test that kvListFormat works as advertised.
func TestKvListFormat(t *testing.T) {
	var emptyPoint *point
	var testKVList = []struct {
		keysValues []interface{}
		want       string
	}{
		{
			keysValues: []interface{}{"data", &dummyStruct{key: "test", value: "info"}},
			want:       ` data={"key-data":"test","value-data":"info"}`,
		},
		{
			keysValues: []interface{}{"data", &dummyStructWithStringMarshal{key: "test", value: "info"}},
			want:       ` data="test=info"`,
		},
		{
			keysValues: []interface{}{"pod", "kubedns"},
			want:       " pod=\"kubedns\"",
		},
		{
			keysValues: []interface{}{"pod", "kubedns", "update", true},
			want:       " pod=\"kubedns\" update=true",
		},
		{
			keysValues: []interface{}{"pod", "kubedns", "spec", struct {
				X int
				Y string
				N time.Time
			}{X: 76, Y: "strval", N: time.Date(2006, 1, 2, 15, 4, 5, .067890e9, time.UTC)}},
			want: ` pod="kubedns" spec={"X":76,"Y":"strval","N":"2006-01-02T15:04:05.06789Z"}`,
		},
		{
			keysValues: []interface{}{"pod", "kubedns", "values", []int{8, 6, 7, 5, 3, 0, 9}},
			want:       " pod=\"kubedns\" values=[8,6,7,5,3,0,9]",
		},
		{
			keysValues: []interface{}{"pod", "kubedns", "values", []string{"deployment", "svc", "configmap"}},
			want:       ` pod="kubedns" values=["deployment","svc","configmap"]`,
		},
		{
			keysValues: []interface{}{"pod", "kubedns", "bytes", []byte("test case for byte array")},
			want:       " pod=\"kubedns\" bytes=\"test case for byte array\"",
		},
		{
			keysValues: []interface{}{"pod", "kubedns", "bytes", []byte("��=� ⌘")},
			want:       " pod=\"kubedns\" bytes=\"\\ufffd\\ufffd=\\ufffd \\u2318\"",
		},
		{
			keysValues: []interface{}{"multiLineString", `Hello world!
	Starts with tab.
  Starts with spaces.
No whitespace.`,
				"pod", "kubedns",
			},
			want: ` multiLineString=<
	Hello world!
		Starts with tab.
	  Starts with spaces.
	No whitespace.
 > pod="kubedns"`,
		},
		{
			keysValues: []interface{}{"pod", "kubedns", "maps", map[string]int{"three": 4}},
			want:       ` pod="kubedns" maps={"three":4}`,
		},
		{
			keysValues: []interface{}{"pod", klog.KRef("kube-system", "kubedns"), "status", "ready"},
			want:       " pod=\"kube-system/kubedns\" status=\"ready\"",
		},
		{
			keysValues: []interface{}{"pod", klog.KRef("", "kubedns"), "status", "ready"},
			want:       " pod=\"kubedns\" status=\"ready\"",
		},
		{
			keysValues: []interface{}{"pod", klog.KObj(test.KMetadataMock{Name: "test-name", NS: "test-ns"}), "status", "ready"},
			want:       " pod=\"test-ns/test-name\" status=\"ready\"",
		},
		{
			keysValues: []interface{}{"pod", klog.KObj(test.KMetadataMock{Name: "test-name", NS: ""}), "status", "ready"},
			want:       " pod=\"test-name\" status=\"ready\"",
		},
		{
			keysValues: []interface{}{"pod", klog.KObj(nil), "status", "ready"},
			want:       " pod=\"\" status=\"ready\"",
		},
		{
			keysValues: []interface{}{"pod", klog.KObj((*test.PtrKMetadataMock)(nil)), "status", "ready"},
			want:       " pod=\"\" status=\"ready\"",
		},
		{
			keysValues: []interface{}{"pod", klog.KObj((*test.KMetadataMock)(nil)), "status", "ready"},
			want:       " pod=\"\" status=\"ready\"",
		},
		{
			keysValues: []interface{}{"pods", klog.KObjs([]test.KMetadataMock{
				{
					Name: "kube-dns",
					NS:   "kube-system",
				},
				{
					Name: "mi-conf",
				},
			})},
			want: ` pods=[{"name":"kube-dns","namespace":"kube-system"},{"name":"mi-conf"}]`,
		},
		{
			keysValues: []interface{}{"point-1", point{100, 200}, "point-2", emptyPoint},
			want:       " point-1=\"x=100, y=200\" point-2=\"<panic: value method k8s.io/klog/v2/internal/serialize_test.point.String called using nil *point pointer>\"",
		},
		{
			keysValues: []interface{}{struct{ key string }{key: "k1"}, "value"},
			want:       " {k1}=\"value\"",
		},
		{
			keysValues: []interface{}{1, "test"},
			want:       " %!s(int=1)=\"test\"",
		},
		{
			keysValues: []interface{}{map[string]string{"k": "key"}, "value"},
			want:       " map[k:key]=\"value\"",
		},
	}

	for _, d := range testKVList {
		b := &bytes.Buffer{}
		serialize.FormatKVs(b, d.keysValues)
		if b.String() != d.want {
			t.Errorf("KVListFormat error:\n got:\n\t%s\nwant:\t%s", b.String(), d.want)
		}
	}
}


================================================
FILE: internal/severity/severity.go
================================================
// Copyright 2013 Google Inc. All Rights Reserved.
// Copyright 2022 The Kubernetes Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package severity provides definitions for klog severity (info, warning, ...)
package severity

import (
	"strings"
)

// severity identifies the sort of log: info, warning etc. The binding to flag.Value
// is handled in klog.go
type Severity int32 // sync/atomic int32

// These constants identify the log levels in order of increasing severity.
// A message written to a high-severity log file is also written to each
// lower-severity log file.
const (
	InfoLog Severity = iota
	WarningLog
	ErrorLog
	FatalLog
	NumSeverity = 4
)

// Char contains one shortcut letter per severity level.
const Char = "IWEF"

// Name contains one name per severity level.
var Name = []string{
	InfoLog:    "INFO",
	WarningLog: "WARNING",
	ErrorLog:   "ERROR",
	FatalLog:   "FATAL",
}

// ByName looks up a severity level by name.
func ByName(s string) (Severity, bool) {
	s = strings.ToUpper(s)
	for i, name := range Name {
		if name == s {
			return Severity(i), true
		}
	}
	return 0, false
}


================================================
FILE: internal/sloghandler/sloghandler_slog.go
================================================
//go:build go1.21
// +build go1.21

/*
Copyright 2023 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package sloghandler

import (
	"context"
	"log/slog"
	"runtime"
	"strings"
	"time"

	"k8s.io/klog/v2/internal/severity"
)

func Handle(_ context.Context, record slog.Record, groups string, printWithInfos func(file string, line int, now time.Time, err error, s severity.Severity, msg string, kvList []interface{})) error {
	now := record.Time
	if now.IsZero() {
		// This format doesn't support printing entries without a time.
		now = time.Now()
	}

	// slog has numeric severity levels, with 0 as default "info", negative for debugging, and
	// positive with some pre-defined levels for more important. Those ranges get mapped to
	// the corresponding klog levels where possible, with "info" the default that is used
	// also for negative debug levels.
	level := record.Level
	s := severity.InfoLog
	switch {
	case level >= slog.LevelError:
		s = severity.ErrorLog
	case level >= slog.LevelWarn:
		s = severity.WarningLog
	}

	var file string
	var line int
	if record.PC != 0 {
		// Same as https://cs.opensource.google/go/x/exp/+/642cacee:slog/record.go;drc=642cacee5cc05231f45555a333d07f1005ffc287;l=70
		fs := runtime.CallersFrames([]uintptr{record.PC})
		f, _ := fs.Next()
		if f.File != "" {
			file = f.File
			if slash := strings.LastIndex(file, "/"); slash >= 0 {
				file = file[slash+1:]
			}
			line = f.Line
		}
	} else {
		file = "???"
		line = 1
	}

	kvList := make([]interface{}, 0, 2*record.NumAttrs())
	record.Attrs(func(attr slog.Attr) bool {
		kvList = appendAttr(groups, kvList, attr)
		return true
	})

	printWithInfos(file, line, now, nil, s, record.Message, kvList)
	return nil
}

func Attrs2KVList(groups string, attrs []slog.Attr) []interface{} {
	kvList := make([]interface{}, 0, 2*len(attrs))
	for _, attr := range attrs {
		kvList = appendAttr(groups, kvList, attr)
	}
	return kvList
}

func appendAttr(groups string, kvList []interface{}, attr slog.Attr) []interface{} {
	var key string
	if groups != "" {
		key = groups + "." + attr.Key
	} else {
		key = attr.Key
	}
	return append(kvList, key, attr.Value)
}


================================================
FILE: internal/test/mock.go
================================================
/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package test contains common code for klog tests.
package test

type KMetadataMock struct {
	Name, NS string
}

func (m KMetadataMock) GetName() string {
	return m.Name
}
func (m KMetadataMock) GetNamespace() string {
	return m.NS
}

type PtrKMetadataMock struct {
	Name, NS string
}

func (m *PtrKMetadataMock) GetName() string {
	return m.Name
}
func (m *PtrKMetadataMock) GetNamespace() string {
	return m.NS
}


================================================
FILE: internal/test/require/require.go
================================================
/*
Copyright 2023 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package require

import "testing"

func NoError(tb testing.TB, err error) {
	if err != nil {
		tb.Helper()
		tb.Fatalf("Unexpected error: %v", err)
	}
}


================================================
FILE: internal/verbosity/helper_test.go
================================================
/*
Copyright 2022 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package verbosity

func enabledInHelper(vs *VState, l Level) bool {
	return vs.Enabled(l, 0)
}


================================================
FILE: internal/verbosity/verbosity.go
================================================
/*
Copyright 2013 Google Inc. All Rights Reserved.
Copyright 2022 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package verbosity

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
)

// New returns a struct that implements -v and -vmodule support. Changing and
// checking these settings is thread-safe, with all concurrency issues handled
// internally.
func New() *VState {
	vs := new(VState)

	// The two fields must have a pointer to the overal struct for their
	// implementation of Set.
	vs.vmodule.vs = vs
	vs.verbosity.vs = vs

	return vs
}

// Value is an extension that makes it possible to use the values in pflag.
type Value interface {
	flag.Value
	Type() string
}

func (vs *VState) V() Value {
	return &vs.verbosity
}

func (vs *VState) VModule() Value {
	return &vs.vmodule
}

// VState contains settings and state. Some of its fields can be accessed
// through atomic read/writes, in other cases a mutex must be held.
type VState struct {
	mu sync.Mutex

	// These flags are modified only under lock, although verbosity may be fetched
	// safely using atomic.LoadInt32.
	vmodule   moduleSpec // The state of the -vmodule flag.
	verbosity levelSpec  // V logging level, the value of the -v flag/

	// pcs is used in V to avoid an allocation when computing the caller's PC.
	pcs [1]uintptr
	// vmap is a cache of the V Level for each V() call site, identified by PC.
	// It is wiped whenever the vmodule flag changes state.
	vmap map[uintptr]Level
	// filterLength stores the length of the vmodule filter chain. If greater
	// than zero, it means vmodule is enabled. It may be read safely
	// using sync.LoadInt32, but is only modified under mu.
	filterLength int32
}

// Level must be an int32 to support atomic read/writes.
type Level int32

type levelSpec struct {
	vs *VState
	l  Level
}

// get returns the value of the level.
func (l *levelSpec) get() Level {
	return Level(atomic.LoadInt32((*int32)(&l.l)))
}

// set sets the value of the level.
func (l *levelSpec) set(val Level) {
	atomic.StoreInt32((*int32)(&l.l), int32(val))
}

// String is part of the flag.Value interface.
func (l *levelSpec) String() string {
	return strconv.FormatInt(int64(l.l), 10)
}

// Get is part of the flag.Getter interface. It returns the
// verbosity level as int32.
func (l *levelSpec) Get() interface{} {
	return int32(l.l)
}

// Type is part of pflag.Value.
func (l *levelSpec) Type() string {
	return "Level"
}

// Set is part of the flag.Value interface.
func (l *levelSpec) Set(value string) error {
	v, err := strconv.ParseInt(value, 10, 32)
	if err != nil {
		return err
	}
	l.vs.mu.Lock()
	defer l.vs.mu.Unlock()
	l.vs.set(Level(v), l.vs.vmodule.filter, false)
	return nil
}

// moduleSpec represents the setting of the -vmodule flag.
type moduleSpec struct {
	vs     *VState
	filter []modulePat
}

// modulePat contains a filter for the -vmodule flag.
// It holds a verbosity level and a file pattern to match.
type modulePat struct {
	pattern string
	literal bool // The pattern is a literal string
	level   Level
}

// match reports whether the file matches the pattern. It uses a string
// comparison if the pattern contains no metacharacters.
func (m *modulePat) match(file string) bool {
	if m.literal {
		return file == m.pattern
	}
	match, _ := filepath.Match(m.pattern, file)
	return match
}

func (m *moduleSpec) String() string {
	// Lock because the type is not atomic. TODO: clean this up.
	// Empty instances don't have and don't need a lock (can
	// happen when flag uses introspection).
	if m.vs != nil {
		m.vs.mu.Lock()
		defer m.vs.mu.Unlock()
	}
	var b bytes.Buffer
	for i, f := range m.filter {
		if i > 0 {
			b.WriteRune(',')
		}
		fmt.Fprintf(&b, "%s=%d", f.pattern, f.level)
	}
	return b.String()
}

// Get is part of the (Go 1.2)  flag.Getter interface. It always returns nil for this flag type since the
// struct is not exported.
func (m *moduleSpec) Get() interface{} {
	return nil
}

// Type is part of pflag.Value
func (m *moduleSpec) Type() string {
	return "pattern=N,..."
}

var errVmoduleSyntax = errors.New("syntax error: expect comma-separated list of filename=N")

// Set will sets module value
// Syntax: -vmodule=recordio=2,file=1,gfs*=3
func (m *moduleSpec) Set(value string) error {
	var filter []modulePat
	for _, pat := range strings.Split(value, ",") {
		if len(pat) == 0 {
			// Empty strings such as from a trailing comma can be ignored.
			continue
		}
		patLev := strings.Split(pat, "=")
		if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 {
			return errVmoduleSyntax
		}
		pattern := patLev[0]
		v, err := strconv.ParseInt(patLev[1], 10, 32)
		if err != nil {
			return errors.New("syntax error: expect comma-separated list of filename=N")
		}
		if v < 0 {
			return errors.New("negative value for vmodule level")
		}
		if v == 0 {
			continue // Ignore. It's harmless but no point in paying the overhead.
		}
		// TODO: check syntax of filter?
		filter = append(filter, modulePat{pattern, isLiteral(pattern), Level(v)})
	}
	m.vs.mu.Lock()
	defer m.vs.mu.Unlock()
	m.vs.set(m.vs.verbosity.l, filter, true)
	return nil
}

// isLiteral reports whether the pattern is a literal string, that is, has no metacharacters
// that require filepath.Match to be called to match the pattern.
func isLiteral(pattern string) bool {
	return !strings.ContainsAny(pattern, `\*?[]`)
}

// set sets a consistent state for V logging.
// The mutex must be held.
func (vs *VState) set(l Level, filter []modulePat, setFilter bool) {
	// Turn verbosity off so V will not fire while we are in transition.
	vs.verbosity.set(0)
	// Ditto for filter length.
	atomic.StoreInt32(&vs.filterLength, 0)

	// Set the new filters and wipe the pc->Level map if the filter has changed.
	if setFilter {
		vs.vmodule.filter = filter
		vs.vmap = make(map[uintptr]Level)
	}

	// Things are consistent now, so enable filtering and verbosity.
	// They are enabled in order opposite to that in V.
	atomic.StoreInt32(&vs.filterLength, int32(len(filter)))
	vs.verbosity.set(l)
}

// Enabled checks whether logging is enabled at the given level. This must be
// called with depth=0 when the caller of enabled will do the logging and
// higher values when more stack levels need to be skipped.
//
// The mutex will be locked only if needed.
func (vs *VState) Enabled(level Level, depth int) bool {
	// This function tries hard to be cheap unless there's work to do.
	// The fast path is two atomic loads and compares.

	// Here is a cheap but safe test to see if V logging is enabled globally.
	if vs.verbosity.get() >= level {
		return true
	}

	// It's off globally but vmodule may still be set.
	// Here is another cheap but safe test to see if vmodule is enabled.
	if atomic.LoadInt32(&vs.filterLength) > 0 {
		// Now we need a proper lock to use the logging structure. The pcs field
		// is shared so we must lock before accessing it. This is fairly expensive,
		// but if V logging is enabled we're slow anyway.
		vs.mu.Lock()
		defer vs.mu.Unlock()
		if runtime.Callers(depth+2, vs.pcs[:]) == 0 {
			return false
		}
		// runtime.Callers returns "return PCs", but we want
		// to look up the symbolic information for the call,
		// so subtract 1 from the PC. runtime.CallersFrames
		// would be cleaner, but allocates.
		pc := vs.pcs[0] - 1
		v, ok := vs.vmap[pc]
		if !ok {
			v = vs.setV(pc)
		}
		return v >= level
	}
	return false
}

// setV computes and remembers the V level for a given PC
// when vmodule is enabled.
// File pattern matching takes the basename of the file, stripped
// of its .go suffix, and uses filepath.Match, which is a little more
// general than the *? matching used in C++.
// Mutex is held.
func (vs *VState) setV(pc uintptr) Level {
	fn := runtime.FuncForPC(pc)
	file, _ := fn.FileLine(pc)
	// The file is something like /a/b/c/d.go. We want just the d.
	file = strings.TrimSuffix(file, ".go")
	if slash := strings.LastIndex(file, "/"); slash >= 0 {
		file = file[slash+1:]
	}
	for _, filter := range vs.vmodule.filter {
		if filter.match(file) {
			vs.vmap[pc] = filter.level
			return filter.level
		}
	}
	vs.vmap[pc] = 0
	return 0
}


================================================
FILE: internal/verbosity/verbosity_test.go
================================================
/*
Copyright 2013 Google Inc. All Rights Reserved.
Copyright 2022 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package verbosity

import (
	"testing"

	"k8s.io/klog/v2/internal/test/require"
)

func TestV(t *testing.T) {
	vs := New()
	require.NoError(t, vs.verbosity.Set("2"))
	depth := 0
	if !vs.Enabled(1, depth) {
		t.Error("not enabled for 1")
	}
	if !vs.Enabled(2, depth) {
		t.Error("not enabled for 2")
	}
	if vs.Enabled(3, depth) {
		t.Error("enabled for 3")
	}
}

func TestVmoduleOn(t *testing.T) {
	vs := New()
	require.NoError(t, vs.vmodule.Set("verbosity_test=2"))
	depth := 0
	if !vs.Enabled(1, depth) {
		t.Error("not enabled for 1")
	}
	if !vs.Enabled(2, depth) {
		t.Error("not enabled for 2")
	}
	if vs.Enabled(3, depth) {
		t.Error("enabled for 3")
	}
	if enabledInHelper(vs, 1) {
		t.Error("enabled for helper at 1")
	}
	if enabledInHelper(vs, 2) {
		t.Error("enabled for helper at 2")
	}
	if enabledInHelper(vs, 3) {
		t.Error("enabled for helper at 3")
	}
}

// vGlobs are patterns that match/don't match this file at V=2.
var vGlobs = map[string]bool{
	// Easy to test the numeric match here.
	"verbosity_test=1": false, // If -vmodule sets V to 1, V(2) will fail.
	"verbosity_test=2": true,
	"verbosity_test=3": true, // If -vmodule sets V to 1, V(3) will succeed.
	// These all use 2 and check the patterns. All are true.
	"*=2":                true,
	"?e*=2":              true,
	"?????????_*=2":      true,
	"??[arx]??????_*t=2": true,
	// These all use 2 and check the patterns. All are false.
	"*x=2":         false,
	"m*=2":         false,
	"??_*=2":       false,
	"?[abc]?_*t=2": false,
}

// Test that vmodule globbing works as advertised.
func testVmoduleGlob(pat string, match bool, t *testing.T) {
	vs := New()
	require.NoError(t, vs.vmodule.Set(pat))
	depth := 0
	actual := vs.Enabled(2, depth)
	if actual != match {
		t.Errorf("incorrect match for %q: got %#v expected %#v", pat, actual, match)
	}
}

// Test that a vmodule globbing works as advertised.
func TestVmoduleGlob(t *testing.T) {
	for glob, match := range vGlobs {
		testVmoduleGlob(glob, match, t)
	}
}


================================================
FILE: k8s_references.go
================================================
/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package klog

import (
	"bytes"
	"fmt"
	"reflect"
	"strings"

	"github.com/go-logr/logr"
)

// ObjectRef references a kubernetes object
type ObjectRef struct {
	Name      string `json:"name"`
	Namespace string `json:"namespace,omitempty"`
}

func (ref ObjectRef) String() string {
	if ref.Namespace != "" {
		var builder strings.Builder
		builder.Grow(len(ref.Namespace) + len(ref.Name) + 1)
		builder.WriteString(ref.Namespace)
		builder.WriteRune('/')
		builder.WriteString(ref.Name)
		return builder.String()
	}
	return ref.Name
}

func (ref ObjectRef) WriteText(out *bytes.Buffer) {
	out.WriteRune('"')
	ref.writeUnquoted(out)
	out.WriteRune('"')
}

func (ref ObjectRef) writeUnquoted(out *bytes.Buffer) {
	if ref.Namespace != "" {
		out.WriteString(ref.Namespace)
		out.WriteRune('/')
	}
	out.WriteString(ref.Name)
}

// MarshalLog ensures that loggers with support for structured output will log
// as a struct by removing the String method via a custom type.
func (ref ObjectRef) MarshalLog() interface{} {
	type or ObjectRef
	return or(ref)
}

var _ logr.Marshaler = ObjectRef{}

// KMetadata is a subset of the kubernetes k8s.io/apimachinery/pkg/apis/meta/v1.Object interface
// this interface may expand in the future, but will always be a subset of the
// kubernetes k8s.io/apimachinery/pkg/apis/meta/v1.Object interface
type KMetadata interface {
	GetName() string
	GetNamespace() string
}

// KObj returns ObjectRef from ObjectMeta
func KObj(obj KMetadata) ObjectRef {
	if obj == nil {
		return ObjectRef{}
	}
	if val := reflect.ValueOf(obj); val.Kind() == reflect.Ptr && val.IsNil() {
		return ObjectRef{}
	}

	return ObjectRef{
		Name:      obj.GetName(),
		Namespace: obj.GetNamespace(),
	}
}

// KRef returns ObjectRef from name and namespace
func KRef(namespace, name string) ObjectRef {
	return ObjectRef{
		Name:      name,
		Namespace: namespace,
	}
}

// KObjs returns slice of ObjectRef from an slice of ObjectMeta
//
// DEPRECATED: Use KObjSlice instead, it has better performance.
func KObjs(arg interface{}) []ObjectRef {
	s := reflect.ValueOf(arg)
	if s.Kind() != reflect.Slice {
		return nil
	}
	objectRefs := make([]ObjectRef, 0, s.Len())
	for i := 0; i < s.Len(); i++ {
		if v, ok := s.Index(i).Interface().(KMetadata); ok {
			objectRefs = append(objectRefs, KObj(v))
		} else {
			return nil
		}
	}
	return objectRefs
}

// KObjSlice takes a slice of objects that implement the KMetadata interface
// and returns an object that gets logged as a slice of ObjectRef values or a
// string containing those values, depending on whether the logger prefers text
// output or structured output.
//
// An error string is logged when KObjSlice is not passed a suitable slice.
//
// Processing of the argument is delayed until the value actually gets logged,
// in contrast to KObjs where that overhead is incurred regardless of whether
// the result is needed.
func KObjSlice(arg interface{}) interface{} {
	return kobjSlice{arg: arg}
}

type kobjSlice struct {
	arg interface{}
}

var _ fmt.Stringer = kobjSlice{}
var _ logr.Marshaler = kobjSlice{}

func (ks kobjSlice) String() string {
	objectRefs, errStr := ks.process()
	if errStr != "" {
		return errStr
	}
	return fmt.Sprintf("%v", objectRefs)
}

func (ks kobjSlice) MarshalLog() interface{} {
	objectRefs, errStr := ks.process()
	if errStr != "" {
		return errStr
	}
	return objectRefs
}

func (ks kobjSlice) process() (objs []interface{}, err string) {
	s := reflect.ValueOf(ks.arg)
	switch s.Kind() {
	case reflect.Invalid:
		// nil parameter, print as nil.
		return nil, ""
	case reflect.Slice:
		// Okay, handle below.
	default:
		return nil, fmt.Sprintf("<KObjSlice needs a slice, got type %T>", ks.arg)
	}
	objectRefs := make([]interface{}, 0, s.Len())
	for i := 0; i < s.Len(); i++ {
		item := s.Index(i).Interface()
		if item == nil {
			objectRefs = append(objectRefs, nil)
		} else if v, ok := item.(KMetadata); ok {
			objectRefs = append(objectRefs, KObj(v))
		} else {
			return nil, fmt.Sprintf("<KObjSlice needs a slice of values implementing KMetadata, got type %T>", item)
		}
	}
	return objectRefs, ""
}

var nilToken = []byte("null")

func (ks kobjSlice) WriteText(out *bytes.Buffer) {
	s := reflect.ValueOf(ks.arg)
	switch s.Kind() {
	case reflect.Invalid:
		// nil parameter, print as null.
		out.Write(nilToken)
		return
	case reflect.Slice:
		// Okay, handle below.
	default:
		fmt.Fprintf(out, `"<KObjSlice needs a slice, got type %T>"`, ks.arg)
		return
	}
	out.Write([]byte{'['})
	defer out.Write([]byte{']'})
	for i := 0; i < s.Len(); i++ {
		if i > 0 {
			out.Write([]byte{','})
		}
		item := s.Index(i).Interface()
		if item == nil {
			out.Write(nilToken)
		} else if v, ok := item.(KMetadata); ok {
			KObj(v).WriteText(out)
		} else {
			fmt.Fprintf(out, `"<KObjSlice needs a slice of values implementing KMetadata, got type %T>"`, item)
			return
		}
	}
}


================================================
FILE: k8s_references_slog.go
================================================
//go:build go1.21
// +build go1.21

/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package klog

import (
	"log/slog"
)

func (ref ObjectRef) LogValue() slog.Value {
	if ref.Namespace != "" {
		return slog.GroupValue(slog.String("name", ref.Name), slog.String("namespace", ref.Namespace))
	}
	return slog.GroupValue(slog.String("name", ref.Name))
}

var _ slog.LogValuer = ObjectRef{}

func (ks kobjSlice) LogValue() slog.Value {
	return slog.AnyValue(ks.MarshalLog())
}

var _ slog.LogValuer = kobjSlice{}


================================================
FILE: klog.go
================================================
// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
//
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package klog contains the following functionality:
//
//   - output routing as defined via command line flags ([InitFlags])
//   - log formatting as text, either with a single, unstructured string ([Info], [Infof], etc.)
//     or as a structured log entry with message and key/value pairs ([InfoS], etc.)
//   - management of a go-logr [Logger] ([SetLogger], [Background], [TODO])
//   - helper functions for logging values ([Format]) and managing the state of klog ([CaptureState], [State.Restore])
//   - wrappers for [logr] APIs for contextual logging where the wrappers can
//     be turned into no-ops ([EnableContextualLogging], [NewContext], [FromContext],
//     [LoggerWithValues], [LoggerWithName]); if the ability to turn off
//     contextual logging is not needed, then go-logr can also be used directly
//   - type aliases for go-logr types to simplify imports in code which uses both (e.g. [Logger])
//   - [k8s.io/klog/v2/textlogger]: a logger which uses the same formatting as klog log with
//     simpler output routing; beware that it comes with its own command line flags
//     and does not use the ones from klog
//   - [k8s.io/klog/v2/ktesting]: per-test output in Go unit tests
//   - [k8s.io/klog/v2/klogr]: a deprecated, standalone [logr.Logger] on top of the main klog package;
//     use [Background] instead if klog output routing is needed, [k8s.io/klog/v2/textlogger] if not
//   - [k8s.io/klog/v2/examples]: demos of this functionality
//   - [k8s.io/klog/v2/test]: reusable tests for [logr.Logger] implementations
//
// Basic examples:
//
//	klog.Info("Prepare to repel boarders")
//
//	klog.Fatalf("Initialization failed: %s", err)
//
// See the documentation for the V function for an explanation of these examples:
//
//	if klog.V(2) {
//		klog.Info("Starting transaction...")
//	}
//
//	klog.V(2).Infoln("Processed", nItems, "elements")
//
// Log output is buffered and written periodically using Flush. Programs
// should call Flush before exiting to guarantee all log output is written.
//
// By default, all log statements write to standard error.
// This package provides several flags that modify this behavior.
// As a result, flag.Parse must be called before any logging is done.
//
//	-logtostderr=true
//		Logs are written to standard error instead of to files.
//		By default, all logs are written regardless of severity
//		(legacy behavior). To filter logs by severity when
//		-logtostderr=true, set -legacy_stderr_threshold_behavior=false
//		and use -stderrthreshold.
//		With -legacy_stderr_threshold_behavior=true,
//		-stderrthreshold has no effect.
//
//		The following flags always have no effect:
//		-alsologtostderr, -alsologtostderrthreshold, and -log_dir.
//		Output redirection at runtime with SetOutput is also ignored.
//	-alsologtostderr=false
//		Logs are written to standard error as well as to files.
//	-alsologtostderrthreshold=INFO
//		Log events at or above this severity are logged to standard
//		error when -alsologtostderr=true (no effect when -logtostderr=true).
//		Default is INFO to maintain backward compatibility.
//	-stderrthreshold=ERROR
//		Log events at or above this severity are logged to standard
//		error as well as to files. When -logtostderr=true, this flag
//		has no effect unless -legacy_stderr_threshold_behavior=false.
//	-legacy_stderr_threshold_behavior=true
//		If true, -stderrthreshold is ignored when -logtostderr=true
//		(legacy behavior). If false, -stderrthreshold is honored even
//		when -logtostderr=true, allowing severity-based filtering.
//	-log_dir=""
//		Log files will be written to this directory instead of the
//		default temporary directory.
//
//	Other flags provide aids to debugging.
//
//	-log_backtrace_at=""
//		When set to a file and line number holding a logging statement,
//		such as
//			-log_backtrace_at=gopherflakes.go:234
//		a stack trace will be written to the Info log whenever execution
//		hits that statement. (Unlike with -vmodule, the ".go" must be
//		present.)
//	-v=0
//		Enable V-leveled logging at the specified level.
//	-vmodule=""
//		The syntax of the argument is a comma-separated list of pattern=N,
//		where pattern is a literal file name (minus the ".go" suffix) or
//		"glob" pattern and N is a V level. For instance,
//			-vmodule=gopher*=3
//		sets the V level to 3 in all Go files whose names begin "gopher".
package klog

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io"
	stdLog "log"
	"math"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"k8s.io/klog/v2/internal/buffer"
	"k8s.io/klog/v2/internal/clock"
	"k8s.io/klog/v2/internal/dbg"
	"k8s.io/klog/v2/internal/serialize"
	"k8s.io/klog/v2/internal/severity"
)

// severityValue identifies the sort of log: info, warning etc. It also implements
// the flag.Value interface. The -stderrthreshold flag is of type severity and
// should be modified only through the flag.Value interface. The values match
// the corresponding constants in C++.
type severityValue struct {
	severity.Severity
}

// get returns the value of the severity.
func (s *severityValue) get() severity.Severity {
	return severity.Severity(atomic.LoadInt32((*int32)(&s.Severity)))
}

// set sets the value of the severity.
func (s *severityValue) set(val severity.Severity) {
	atomic.StoreInt32((*int32)(&s.Severity), int32(val))
}

// String is part of the flag.Value interface.
func (s *severityValue) String() string {
	return strconv.FormatInt(int64(s.Severity), 10)
}

// Get is part of the flag.Getter interface.
func (s *severityValue) Get() interface{} {
	return s.Severity
}

// Set is part of the flag.Value interface.
func (s *severityValue) Set(value string) error {
	var threshold severity.Severity
	// Is it a known name?
	if v, ok := severity.ByName(value); ok {
		threshold = v
	} else {
		v, err := strconv.ParseInt(value, 10, 32)
		if err != nil {
			return err
		}
		threshold = severity.Severity(v)
	}
	s.set(threshold)
	return nil
}

// OutputStats tracks the number of output lines and bytes written.
type OutputStats struct {
	lines int64
	bytes int64
}

// Lines returns the number of lines written.
func (s *OutputStats) Lines() int64 {
	return atomic.LoadInt64(&s.lines)
}

// Bytes returns the number of bytes written.
func (s *OutputStats) Bytes() int64 {
	return atomic.LoadInt64(&s.bytes)
}

// Stats tracks the number of lines of output and number of bytes
// per severity level. Values must be read with atomic.LoadInt64.
var Stats struct {
	Info, Warning, Error OutputStats
}

var severityStats = [severity.NumSeverity]*OutputStats{
	severity.InfoLog:    &Stats.Info,
	severity.WarningLog: &Stats.Warning,
	severity.ErrorLog:   &Stats.Error,
}

// Level is exported because it appears in the arguments to V and is
// the type of the v flag, which can be set programmatically.
// It's a distinct type because we want to discriminate it from logType.
// Variables of type level are only changed under logging.mu.
// The -v flag is read only with atomic ops, so the state of the logging
// module is consistent.

// Level is treated as a sync/atomic int32.

// Level specifies a level of verbosity for V logs. *Level implements
// flag.Value; the -v flag is of type Level and should be modified
// only through the flag.Value interface.
type Level int32

// get returns the value of the Level.
func (l *Level) get() Level {
	return Level(atomic.LoadInt32((*int32)(l)))
}

// set sets the value of the Level.
func (l *Level) set(val Level) {
	atomic.StoreInt32((*int32)(l), int32(val))
}

// String is part of the flag.Value interface.
func (l *Level) String() string {
	return strconv.FormatInt(int64(*l), 10)
}

// Get is part of the flag.Getter interface.
func (l *Level) Get() interface{} {
	return *l
}

// Set is part of the flag.Value interface.
func (l *Level) Set(value string) error {
	v, err := strconv.ParseInt(value, 10, 32)
	if err != nil {
		return err
	}
	logging.mu.Lock()
	defer logging.mu.Unlock()
	logging.setVState(Level(v), logging.vmodule.filter, false)
	return nil
}

// moduleSpec represents the setting of the -vmodule flag.
type moduleSpec struct {
	filter []modulePat
}

// modulePat contains a filter for the -vmodule flag.
// It holds a verbosity level and a file pattern to match.
type modulePat struct {
	pattern string
	literal bool // The pattern is a literal string
	level   Level
}

// match reports whether the file matches the pattern. It uses a string
// comparison if the pattern contains no metacharacters.
func (m *modulePat) match(file string) bool {
	if m.literal {
		return file == m.pattern
	}
	match, _ := filepath.Match(m.pattern, file)
	return match
}

func (m *moduleSpec) String() string {
	// Lock because the type is not atomic. TODO: clean this up.
	logging.mu.Lock()
	defer logging.mu.Unlock()
	return m.serialize()
}

func (m *moduleSpec) serialize() string {
	var b bytes.Buffer
	for i, f := range m.filter {
		if i > 0 {
			b.WriteRune(',')
		}
		fmt.Fprintf(&b, "%s=%d", f.pattern, f.level)
	}
	return b.String()
}

// Get is part of the (Go 1.2)  flag.Getter interface. It always returns nil for this flag type since the
// struct is not exported.
func (m *moduleSpec) Get() interface{} {
	return nil
}

var errVmoduleSyntax = errors.New("syntax error: expect comma-separated list of filename=N")

// Set will sets module value
// Syntax: -vmodule=recordio=2,file=1,gfs*=3
func (m *moduleSpec) Set(value string) error {
	filter, err := parseModuleSpec(value)
	if err != nil {
		return err
	}
	logging.mu.Lock()
	defer logging.mu.Unlock()
	logging.setVState(logging.verbosity, filter, true)
	return nil
}

func parseModuleSpec(value string) ([]modulePat, error) {
	var filter []modulePat
	for _, pat := range strings.Split(value, ",") {
		if len(pat) == 0 {
			// Empty strings such as from a trailing comma can be ignored.
			continue
		}
		patLev := strings.Split(pat, "=")
		if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 {
			return nil, errVmoduleSyntax
		}
		pattern := patLev[0]
		v, err := strconv.ParseInt(patLev[1], 10, 32)
		if err != nil {
			return nil, errors.New("syntax error: expect comma-separated list of filename=N")
		}
		if v < 0 {
			return nil, errors.New("negative value for vmodule level")
		}
		if v == 0 {
			continue // Ignore. It's harmless but no point in paying the overhead.
		}
		// TODO: check syntax of filter?
		filter = append(filter, modulePat{pattern, isLiteral(pattern), Level(v)})
	}
	return filter, nil
}

// isLiteral reports whether the pattern is a literal string, that is, has no metacharacters
// that require filepath.Match to be called to match the pattern.
func isLiteral(pattern string) bool {
	return !strings.ContainsAny(pattern, `\*?[]`)
}

// traceLocation represents the setting of the -log_backtrace_at flag.
type traceLocation struct {
	file string
	line int
}

// isSet reports whether the trace location has been specified.
// logging.mu is held.
func (t *traceLocation) isSet() bool {
	return t.line > 0
}

// match reports whether the specified file and line matches the trace location.
// The argument file name is the full path, not the basename specified in the flag.
// logging.mu is held.
func (t *traceLocation) match(file string, line int) bool {
	if t.line != line {
		return false
	}
	if i := strings.LastIndex(file, "/"); i >= 0 {
		file = file[i+1:]
	}
	return t.file == file
}

func (t *traceLocation) String() string {
	// Lock because the type is not atomic. TODO: clean this up.
	logging.mu.Lock()
	defer logging.mu.Unlock()
	return fmt.Sprintf("%s:%d", t.file, t.line)
}

// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the
// struct is not exported
func (t *traceLocation) Get() interface{} {
	return nil
}

var errTraceSyntax = errors.New("syntax error: expect file.go:234")

// Set will sets backtrace value
// Syntax: -log_backtrace_at=gopherflakes.go:234
// Note that unlike vmodule the file extension is included here.
func (t *traceLocation) Set(value string) error {
	if value == "" {
		// Unset.
		logging.mu.Lock()
		defer logging.mu.Unlock()
		t.line = 0
		t.file = ""
		return nil
	}
	fields := strings.Split(value, ":")
	if len(fields) != 2 {
		return errTraceSyntax
	}
	file, line := fields[0], fields[1]
	if !strings.Contains(file, ".") {
		return errTraceSyntax
	}
	v, err := strconv.Atoi(line)
	if err != nil {
		return errTraceSyntax
	}
	if v <= 0 {
		return errors.New("negative or zero value for level")
	}
	logging.mu.Lock()
	defer logging.mu.Unlock()
	t.line = v
	t.file = file
	return nil
}

var logging loggingT
var commandLine flag.FlagSet

// init sets up the defaults and creates command line flags.
func init() {
	// Initialize severity thresholds
	logging.stderrThreshold = severityValue{
		Severity: severity.ErrorLog, // Default stderrThreshold is ERROR.
	}
	logging.alsologtostderrthreshold = severityValue{
		Severity: severity.InfoLog, // Default alsologtostderrthreshold is INFO (to maintain backward compatibility).
	}
	logging.setVState(0, nil, false)

	commandLine.StringVar(&logging.logDir, "log_dir", "", "If non-empty, write log files in this directory (no effect when -logtostderr=true)")
	commandLine.StringVar(&logging.logFile, "log_file", "", "If non-empty, use this log file (no effect when -logtostderr=true)")
	commandLine.Uint64Var(&logging.logFileMaxSizeMB, "log_file_max_size", 1800,
		"Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. "+
			"If the value is 0, the maximum file size is unlimited.")
	commandLine.BoolVar(&logging.toStderr, "logtostderr", true, "log to standard error instead of files")
	commandLine.BoolVar(&logging.alsoToStderr, "alsologtostderr", false, "log to standard error as well as files (no effect when -logtostderr=true)")
	commandLine.BoolVar(&logging.legacyStderrThresholdBehavior, "legacy_stderr_threshold_behavior", true, "If true, stderrthreshold is ignored when logtostderr=true (legacy behavior). If false, stderrthreshold is honored even when logtostderr=true")
	commandLine.Var(&logging.verbosity, "v", "number for the log level verbosity")
	commandLine.BoolVar(&logging.addDirHeader, "add_dir_header", false, "If true, adds the file directory to the header of the log messages")
	commandLine.BoolVar(&logging.skipHeaders, "skip_headers", false, "If true, avoid header prefixes in the log messages")
	commandLine.BoolVar(&logging.oneOutput, "one_output", false, "If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true)")
	commandLine.BoolVar(&logging.skipLogHeaders, "skip_log_headers", false, "If true, avoid headers when opening log files (no effect when -logtostderr=true)")
	commandLine.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=true unless -legacy_stderr_threshold_behavior=false)")
	commandLine.Var(&logging.alsologtostderrthreshold, "alsologtostderrthreshold", "logs at or above this threshold go to stderr when -alsologtostderr=true (no effect when -logtostderr=true)")
	commandLine.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging")
	commandLine.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace")

	logging.settings.contextualLoggingEnabled = true
	logging.flushD = newFlushDaemon(logging.lockAndFlushAll, nil)
}

// InitFlags is for explicitly initializing the flags.
// It may get called repeatedly for different flagsets, but not
// twice for the same one. May get called concurrently
// to other goroutines using klog. However, only some flags
// may get set concurrently (see implementation).
func InitFlags(flagset *flag.FlagSet) {
	if flagset == nil {
		flagset = flag.CommandLine
	}

	commandLine.VisitAll(func(f *flag.Flag) {
		flagset.Var(f.Value, f.Name, f.Usage)
	})
}

// Flush flushes all pending log I/O.
func Flush() {
	logging.lockAndFlushAll()
}

// settings collects global settings.
type settings struct {
	// contextualLoggingEnabled controls whether contextual logging is
	// active. Disabling it may have some small performance benefit.
	contextualLoggingEnabled bool

	// logger is the global Logger chosen by users of klog, nil if
	// none is available.
	logger *logWriter

	// loggerOptions contains the options that were supplied for
	// globalLogger.
	loggerOptions loggerOptions

	// Boolean flags. Not handled atomically because the flag.Value interface
	// does not let us avoid the =true, and that shorthand is necessary for
	// compatibility. TODO: does this matter enough to fix? Seems unlikely.
	toStderr                      bool // The -logtostderr flag.
	alsoToStderr                  bool // The -alsologtostderr flag.
	legacyStderrThresholdBehavior bool // The -legacy_stderr_threshold_behavior flag.

	// Level flag. Handled atomically.
	stderrThreshold          severityValue // The -stderrthreshold flag.
	alsologtostderrthreshold severityValue // The -alsologtostderrthreshold flag.

	// Access to all of the following fields must be protected via a mutex.

	// file holds writer for each of the log types.
	file [severity.NumSeverity]io.Writer
	// flushInterval is the interval for periodic flushing. If zero,
	// the global default will be used.
	flushInterval time.Duration

	// filterLength stores the length of the vmodule filter chain. If greater
	// than zero, it means vmodule is enabled. It may be read safely
	// using sync.LoadInt32, but is only modified under mu.
	filterLength int32
	// traceLocation is the state of the -log_backtrace_at flag.
	traceLocation traceLocation
	// These flags are modified only under lock, although verbosity may be fetched
	// safely using atomic.LoadInt32.
	vmodule   moduleSpec // The state of the -vmodule flag.
	verbosity Level      // V logging level, the value of the -v flag/

	// If non-empty, overrides the choice of directory in which to write logs.
	// See createLogDirs for the full list of possible destinations.
	logDir string

	// If non-empty, specifies the path of the file to write logs. mutually exclusive
	// with the log_dir option.
	logFile string

	// When logFile is specified, this limiter makes sure the logFile won't exceeds a certain size. When exceeds, the
	// logFile will be cleaned up. If this value is 0, no size limitation will be applied to logFile.
	logFileMaxSizeMB uint64

	// If true, do not add the prefix headers, useful when used with SetOutput
	skipHeaders bool

	// If true, do not add the headers to log files
	skipLogHeaders bool

	// If true, add the file directory to the header
	addDirHeader bool

	// If true, messages will not be propagated to lower severity log levels
	oneOutput bool

	// If set, all output will be filtered through the filter.
	filter LogFilter
}

// deepCopy creates a copy that doesn't share anything with the original
// instance.
func (s settings) deepCopy() settings {
	// vmodule is a slice and would be shared, so we have copy it.
	filter := make([]modulePat, len(s.vmodule.filter))
	copy(filter, s.vmodule.filter)
	s.vmodule.filter = filter

	if s.logger != nil {
		logger := *s.logger
		s.logger = &logger
	}

	return s
}

// loggingT collects all the global state of the logging setup.
type loggingT struct {
	settings

	// flushD holds a flushDaemon that frequently flushes log file buffers.
	// Uses its own mutex.
	flushD *flushDaemon

	// mu protects the remaining elements of this structure and the fields
	// in settingsT which need a mutex lock.
	mu sync.Mutex

	// pcs is used in V to avoid an allocation when computing the caller's PC.
	pcs [1]uintptr
	// vmap is a cache of the V Level for each V() call site, identified by PC.
	// It is wiped whenever the vmodule flag changes state.
	vmap map[uintptr]Level
}

// setVState sets a consistent state for V logging.
// l.mu is held.
func (l *loggingT) setVState(verbosity Level, filter []modulePat, setFilter bool) {
	// Turn verbosity off so V will not fire while we are in transition.
	l.verbosity.set(0)
	// Ditto for filter length.
	atomic.StoreInt32(&l.filterLength, 0)

	// Set the new filters and wipe the pc->Level map if the filter has changed.
	if setFilter {
		l.vmodule.filter = filter
		l.vmap = make(map[uintptr]Level)
	}

	// Things are consistent now, so enable filtering and verbosity.
	// They are enabled in order opposite to that in V.
	atomic.StoreInt32(&l.filterLength, int32(len(filter)))
	l.verbosity.set(verbosity)
}

var timeNow = time.Now // Stubbed out for testing.

// CaptureState gathers information about all current klog settings.
// The result can be used to restore those settings.
func CaptureState() State {
	logging.mu.Lock()
	defer logging.mu.Unlock()
	return &state{
		settings:      logging.settings.deepCopy(),
		flushDRunning: logging.flushD.isRunning(),
		maxSize:       MaxSize,
	}
}

// State stores a snapshot of klog settings. It gets created with CaptureState
// and can be used to restore the entire state. Modifying individual settings
// is supported via the command line flags.
type State interface {
	// Restore restore the entire state. It may get called more than once.
	Restore()
}

type state struct {
	settings

	flushDRunning bool
	maxSize       uint64
}

func (s *state) Restore() {
	// This needs to be done before mutex locking.
	if s.flushDRunning && !logging.flushD.isRunning() {
		// This is not quite accurate: StartFlushDaemon might
		// have been called with some different interval.
		interval := s.flushInterval
		if interval == 0 {
			interval = flushInterval
		}
		logging.flushD.run(interval)
	} else if !s.flushDRunning && logging.flushD.isRunning() {
		logging.flushD.stop()
	}

	logging.mu.Lock()
	defer logging.mu.Unlock()

	logging.settings = s.settings
	logging.setVState(s.verbosity, s.vmodule.filter, true)
	MaxSize = s.maxSize
}

/*
header formats a log header as defined by the C++ implementation.
It returns a buffer containing the formatted header and the user's file and line number.
The depth specifies how many stack frames above lives the source line to be identified in the log message.

Log lines have this form:

	Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...

where the fields are defined as follows:

	L                A single character, representing the log level (eg 'I' for INFO)
	mm               The month (zero padded; ie May is '05')
	dd               The day (zero padded)
	hh:mm:ss.uuuuuu  Time in hours, minutes and fractional seconds
	threadid         The space-padded thread ID as returned by GetTID()
	file             The file name
	line             The line number
	msg              The user-supplied message
*/
func (l *loggingT) header(s severity.Severity, depth int) (*buffer.Buffer, string, int) {
	_, file, line, ok := runtime.Caller(3 + depth)
	if !ok {
		file = "???"
		line = 1
	} else {
		if slash := strings.LastIndex(file, "/"); slash >= 0 {
			path := file
			file = path[slash+1:]
			if l.addDirHeader {
				if dirsep := strings.LastIndex(path[:slash], "/"); dirsep >= 0 {
					file = path[dirsep+1:]
				}
			}
		}
	}
	return l.formatHeader(s, file, line, timeNow()), file, line
}

// formatHeader formats a log header using the provided file name and line number.
func (l *loggingT) formatHeader(s severity.Severity, file string, line int, now time.Time) *buffer.Buffer {
	buf := buffer.GetBuffer()
	if l.skipHeaders {
		return buf
	}
	buf.FormatHeader(s, file, line, now)
	return buf
}

func (l *loggingT) println(s severity.Severity, logger *logWriter, filter LogFilter, args ...interface{}) {
	l.printlnDepth(s, logger, filter, 1, args...)
}

func (l *loggingT) printlnDepth(s severity.Severity, logger *logWriter, filter LogFilter, depth int, args ...interface{}) {
	if false {
		_ = fmt.Sprintln(args...) // cause vet to treat this function like fmt.Println
	}

	buf, file, line := l.header(s, depth)
	// If a logger is set and doesn't support writing a formatted buffer,
	// we clear the generated header as we rely on the backing
	// logger implementation to print headers.
	if logger != nil && logger.writeKlogBuffer == nil {
		buffer.PutBuffer(buf)
		buf = buffer.GetBuffer()
	}
	if filter != nil {
		args = filter.Filter(args)
	}
	fmt.Fprintln(buf, args...)
	l.output(s, logger, buf, depth, file, line, false)
}

func (l *loggingT) print(s severity.Severity, logger *logWriter, filter LogFilter, args 
Download .txt
gitextract_iyzg6fyz/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── lint.yml
│       └── test.yml
├── .gitignore
├── .golangci.yaml
├── CONTRIBUTING.md
├── LICENSE
├── OWNERS
├── README.md
├── RELEASE.md
├── SECURITY.md
├── SECURITY_CONTACTS
├── code-of-conduct.md
├── contextual.go
├── contextual_slog.go
├── contextual_slog_example_test.go
├── contextual_test.go
├── examples/
│   ├── benchmarks/
│   │   └── benchmarks_test.go
│   ├── coexist_glog/
│   │   └── coexist_glog.go
│   ├── coexist_klog_v1_and_v2/
│   │   ├── coexist_klog_v1_and_v2.go
│   │   └── go.mod
│   ├── flushing/
│   │   ├── .gitignore
│   │   └── flushing_test.go
│   ├── go.mod
│   ├── go.sum
│   ├── go_vet/
│   │   ├── go_vet_test.go
│   │   └── testdata/
│   │       └── calls.go
│   ├── klogr/
│   │   └── main.go
│   ├── log_file/
│   │   └── usage_log_file.go
│   ├── output_test/
│   │   └── output_test.go
│   ├── set_output/
│   │   └── usage_set_output.go
│   ├── stderr_threshold_fix/
│   │   └── main.go
│   ├── structured_logging/
│   │   └── structured_logging.go
│   └── util/
│       └── require/
│           └── require.go
├── exit.go
├── exit_test.go
├── format.go
├── format_test.go
├── go.mod
├── go.sum
├── hack/
│   └── verify-apidiff.sh
├── imports.go
├── integration_tests/
│   ├── internal/
│   │   └── main.go
│   └── klog_test.go
├── internal/
│   ├── buffer/
│   │   └── buffer.go
│   ├── clock/
│   │   ├── README.md
│   │   ├── clock.go
│   │   └── testing/
│   │       ├── fake_clock.go
│   │       └── simple_interval_clock.go
│   ├── dbg/
│   │   └── dbg.go
│   ├── serialize/
│   │   ├── keyvalues.go
│   │   ├── keyvalues_no_slog.go
│   │   ├── keyvalues_slog.go
│   │   └── keyvalues_test.go
│   ├── severity/
│   │   └── severity.go
│   ├── sloghandler/
│   │   └── sloghandler_slog.go
│   ├── test/
│   │   ├── mock.go
│   │   └── require/
│   │       └── require.go
│   └── verbosity/
│       ├── helper_test.go
│       ├── verbosity.go
│       └── verbosity_test.go
├── k8s_references.go
├── k8s_references_slog.go
├── klog.go
├── klog_file.go
├── klog_file_others.go
├── klog_file_windows.go
├── klog_test.go
├── klog_wrappers_test.go
├── klogr/
│   ├── README.md
│   ├── calldepth-test/
│   │   ├── call_depth_helper_test.go
│   │   └── call_depth_main_test.go
│   ├── klogr.go
│   ├── klogr_test.go
│   └── output_test.go
├── klogr.go
├── klogr_helper_test.go
├── klogr_slog.go
├── klogr_slog_test.go
├── klogr_test.go
├── ktesting/
│   ├── contextual_test.go
│   ├── example/
│   │   └── example_test.go
│   ├── example_test.go
│   ├── helper_test.go
│   ├── init/
│   │   └── init.go
│   ├── main_test.go
│   ├── options.go
│   ├── setup.go
│   ├── testinglogger.go
│   └── testinglogger_test.go
├── output_test.go
├── safeptr.go
├── safeptr_test.go
├── stderr_threshold_test.go
├── test/
│   ├── output.go
│   ├── output_helper.go
│   └── zapr.go
└── textlogger/
    ├── example_test.go
    ├── options.go
    ├── output_test.go
    ├── textlogger.go
    ├── textlogger_slog.go
    ├── textlogger_slog_test.go
    └── textlogger_test.go
Download .txt
SYMBOL INDEX (705 symbols across 81 files)

FILE: contextual.go
  function SetLogger (line 59) | func SetLogger(logger logr.Logger) {
  function SetLoggerWithOptions (line 72) | func SetLoggerWithOptions(logger logr.Logger, opts ...LoggerOption) {
  function ContextualLogger (line 86) | func ContextualLogger(enabled bool) LoggerOption {
  function FlushLogger (line 93) | func FlushLogger(flush func()) LoggerOption {
  function WriteKlogBuffer (line 109) | func WriteKlogBuffer(write func([]byte)) LoggerOption {
  type LoggerOption (line 117) | type LoggerOption
  type loggerOptions (line 119) | type loggerOptions struct
  type logWriter (line 126) | type logWriter struct
  function ClearLogger (line 136) | func ClearLogger() {
  function EnableContextualLogging (line 149) | func EnableContextualLogging(enabled bool) {
  function FromContext (line 156) | func FromContext(ctx context.Context) Logger {
  function TODO (line 169) | func TODO() Logger {
  function Background (line 177) | func Background() Logger {
  function LoggerWithValues (line 189) | func LoggerWithValues(logger Logger, kv ...interface{}) Logger {
  function LoggerWithName (line 198) | func LoggerWithName(logger Logger, name string) Logger {
  function NewContext (line 207) | func NewContext(ctx context.Context, logger Logger) context.Context {

FILE: contextual_slog.go
  function SetSlogLogger (line 29) | func SetSlogLogger(logger *slog.Logger) {

FILE: contextual_slog_example_test.go
  function ExampleSetSlogLogger (line 29) | func ExampleSetSlogLogger() {

FILE: contextual_test.go
  function ExampleSetLogger (line 29) | func ExampleSetLogger() {
  function ExampleFlushLogger (line 50) | func ExampleFlushLogger() {
  function BenchmarkPassingLogger (line 63) | func BenchmarkPassingLogger(b *testing.B) {
  function BenchmarkExtractLogger (line 83) | func BenchmarkExtractLogger(b *testing.B) {
  function passCtx (line 95) | func passCtx(ctx context.Context) context.Context { return ctx }
  function extractCtx (line 98) | func extractCtx(ctx context.Context) klog.Logger { return klog.FromConte...
  function passLogger (line 101) | func passLogger(logger klog.Logger) klog.Logger { return logger }

FILE: examples/benchmarks/benchmarks_test.go
  constant verbosityThreshold (line 35) | verbosityThreshold = 10
  function init (line 38) | func init() {
  type testcase (line 49) | type testcase struct
  function BenchmarkOutput (line 54) | func BenchmarkOutput(b *testing.B) {
  function newZaprLogger (line 147) | func newZaprLogger() logr.Logger {
  type KMetadataMock (line 163) | type KMetadataMock struct
    method GetName (line 167) | func (m KMetadataMock) GetName() string {
    method GetNamespace (line 170) | func (m KMetadataMock) GetNamespace() string {
  type discard (line 174) | type discard struct
    method Write (line 178) | func (discard) Write(p []byte) (int, error) {

FILE: examples/coexist_glog/coexist_glog.go
  function main (line 11) | func main() {

FILE: examples/coexist_klog_v1_and_v2/coexist_klog_v1_and_v2.go
  constant OutputCallDepth (line 11) | OutputCallDepth = 6
  constant DefaultPrefixLength (line 14) | DefaultPrefixLength = 53
  type klogWriter (line 18) | type klogWriter struct
    method Write (line 20) | func (kw klogWriter) Write(p []byte) (n int, err error) {
  function main (line 39) | func main() {

FILE: examples/flushing/flushing_test.go
  function main (line 13) | func main() {
  function TestLeakingFlushDaemon (line 35) | func TestLeakingFlushDaemon(t *testing.T) {

FILE: examples/go_vet/go_vet_test.go
  function TestGoVet (line 31) | func TestGoVet(t *testing.T) {

FILE: examples/go_vet/testdata/calls.go
  function calls (line 23) | func calls() {

FILE: examples/klogr/main.go
  type myError (line 11) | type myError struct
    method Error (line 15) | func (e myError) Error() string {
  function main (line 19) | func main() {

FILE: examples/log_file/usage_log_file.go
  function main (line 10) | func main() {

FILE: examples/output_test/output_test.go
  function newLogger (line 39) | func newLogger(out io.Writer, v int, _ string) logr.Logger {
  function TestZaprOutput (line 44) | func TestZaprOutput(t *testing.T) {
  function BenchmarkZaprOutput (line 55) | func BenchmarkZaprOutput(b *testing.B) {
  function TestKlogrStackText (line 61) | func TestKlogrStackText(t *testing.T) {
  function TestKlogrStackZapr (line 85) | func TestKlogrStackZapr(t *testing.T) {
  function TestKlogrInternalStackText (line 126) | func TestKlogrInternalStackText(t *testing.T) {
  function TestKlogrInternalStackZapr (line 150) | func TestKlogrInternalStackZapr(t *testing.T) {
  function newZaprLogger (line 190) | func newZaprLogger(out io.Writer, v int) logr.Logger {

FILE: examples/set_output/usage_set_output.go
  function main (line 12) | func main() {

FILE: examples/stderr_threshold_fix/main.go
  function main (line 10) | func main() {

FILE: examples/structured_logging/structured_logging.go
  type MyStruct (line 10) | type MyStruct struct
  type MyString (line 17) | type MyString
    method String (line 19) | func (m MyString) String() string {
  function main (line 23) | func main() {

FILE: examples/util/require/require.go
  function NoError (line 3) | func NoError(err error) {

FILE: exit.go
  function FlushAndExit (line 49) | func FlushAndExit(flushTimeout time.Duration, exitCode int) {
  function timeoutFlush (line 58) | func timeoutFlush(timeout time.Duration) {

FILE: exit_test.go
  function ExampleFlushAndExit (line 25) | func ExampleFlushAndExit() {

FILE: format.go
  function Format (line 37) | func Format(obj interface{}) interface{} {
  type formatAny (line 41) | type formatAny struct
    method String (line 45) | func (f formatAny) String() string {
    method MarshalLog (line 55) | func (f formatAny) MarshalLog() interface{} {

FILE: format_test.go
  function TestFormat (line 30) | func TestFormat(t *testing.T) {
  function assertEqual (line 58) | func assertEqual(t *testing.T, expected, actual, what string) {
  type TypeMeta (line 64) | type TypeMeta struct
    method String (line 68) | func (t TypeMeta) String() string {
    method MarshalLog (line 72) | func (t TypeMeta) MarshalLog() interface{} {
  type config (line 76) | type config struct

FILE: integration_tests/internal/main.go
  function main (line 24) | func main() {
  function getEnvOrDie (line 39) | func getEnvOrDie(name string) string {

FILE: integration_tests/klog_test.go
  constant infoLog (line 18) | infoLog    = "this is a info log line"
  constant warningLog (line 19) | warningLog = "this is a warning log line"
  constant errorLog (line 20) | errorLog   = "this is a error log line"
  constant fatalLog (line 21) | fatalLog   = "this is a fatal log line"
  function TestDestinationsWithDifferentFlags (line 58) | func TestDestinationsWithDifferentFlags(t *testing.T) {
  constant klogExampleGoFile (line 279) | klogExampleGoFile = "./internal/main.go"
  function klogRun (line 283) | func klogRun(t *testing.T, flags []string, stderr io.Writer) {
  function getFileContent (line 310) | func getFileContent(t *testing.T, filePath string) string {
  function assertFileIsAbsent (line 318) | func assertFileIsAbsent(t *testing.T, filePath string) {
  function checkForLogs (line 324) | func checkForLogs(t *testing.T, expected, disallowed res, content, name ...
  function checkExpected (line 333) | func checkExpected(t *testing.T, expected bool, where string, haystack s...
  function withTmpDir (line 344) | func withTmpDir(t *testing.T, f func(string)) {
  function getLogFilePath (line 361) | func getLogFilePath(dir, binaryName, levelName string) (string, error) {

FILE: internal/buffer/buffer.go
  type Buffer (line 40) | type Buffer struct
    method twoDigits (line 79) | func (buf *Buffer) twoDigits(i, d int) {
    method nDigits (line 88) | func (buf *Buffer) nDigits(n, i, d int, pad byte) {
    method someDigits (line 100) | func (buf *Buffer) someDigits(i, d int) int {
    method FormatHeader (line 117) | func (buf *Buffer) FormatHeader(s severity.Severity, file string, line...
    method SprintHeader (line 158) | func (buf *Buffer) SprintHeader(s severity.Severity, now time.Time) st...
  function GetBuffer (line 52) | func GetBuffer() *Buffer {
  function PutBuffer (line 59) | func PutBuffer(b *Buffer) {
  constant digits (line 76) | digits = "0123456789"

FILE: internal/clock/clock.go
  type PassiveClock (line 24) | type PassiveClock interface
  type Clock (line 31) | type Clock interface
  type WithDelayedExecution (line 48) | type WithDelayedExecution interface
  type WithTickerAndDelayedExecution (line 58) | type WithTickerAndDelayedExecution interface
  type Ticker (line 67) | type Ticker interface
  type RealClock (line 75) | type RealClock struct
    method Now (line 78) | func (RealClock) Now() time.Time {
    method Since (line 83) | func (RealClock) Since(ts time.Time) time.Duration {
    method After (line 90) | func (RealClock) After(d time.Duration) <-chan time.Time {
    method NewTimer (line 95) | func (RealClock) NewTimer(d time.Duration) Timer {
    method AfterFunc (line 102) | func (RealClock) AfterFunc(d time.Duration, f func()) Timer {
    method NewTicker (line 109) | func (RealClock) NewTicker(d time.Duration) Ticker {
    method Sleep (line 117) | func (RealClock) Sleep(d time.Duration) {
  type Timer (line 123) | type Timer interface
  type realTimer (line 132) | type realTimer struct
    method C (line 137) | func (r *realTimer) C() <-chan time.Time {
    method Stop (line 142) | func (r *realTimer) Stop() bool {
    method Reset (line 147) | func (r *realTimer) Reset(d time.Duration) bool {
  type realTicker (line 151) | type realTicker struct
    method C (line 155) | func (r *realTicker) C() <-chan time.Time {
    method Stop (line 159) | func (r *realTicker) Stop() {

FILE: internal/clock/testing/fake_clock.go
  type FakePassiveClock (line 32) | type FakePassiveClock struct
    method Now (line 69) | func (f *FakePassiveClock) Now() time.Time {
    method Since (line 76) | func (f *FakePassiveClock) Since(ts time.Time) time.Duration {
    method SetTime (line 83) | func (f *FakePassiveClock) SetTime(t time.Time) {
  type FakeClock (line 38) | type FakeClock struct
    method After (line 90) | func (f *FakeClock) After(d time.Duration) <-chan time.Time {
    method NewTimer (line 103) | func (f *FakeClock) NewTimer(d time.Duration) clock.Timer {
    method AfterFunc (line 120) | func (f *FakeClock) AfterFunc(d time.Duration, cb func()) clock.Timer {
    method Tick (line 139) | func (f *FakeClock) Tick(d time.Duration) <-chan time.Time {
    method NewTicker (line 158) | func (f *FakeClock) NewTicker(d time.Duration) clock.Ticker {
    method Step (line 177) | func (f *FakeClock) Step(d time.Duration) {
    method SetTime (line 184) | func (f *FakeClock) SetTime(t time.Time) {
    method setTimeLocked (line 191) | func (f *FakeClock) setTimeLocked(t time.Time) {
    method HasWaiters (line 228) | func (f *FakeClock) HasWaiters() bool {
    method Sleep (line 235) | func (f *FakeClock) Sleep(d time.Duration) {
  type fakeClockWaiter (line 45) | type fakeClockWaiter struct
  function NewFakePassiveClock (line 55) | func NewFakePassiveClock(t time.Time) *FakePassiveClock {
  function NewFakeClock (line 62) | func NewFakeClock(t time.Time) *FakeClock {
  type IntervalClock (line 243) | type IntervalClock struct
    method Now (line 249) | func (i *IntervalClock) Now() time.Time {
    method Since (line 255) | func (i *IntervalClock) Since(ts time.Time) time.Duration {
    method After (line 261) | func (*IntervalClock) After(time.Duration) <-chan time.Time {
    method NewTimer (line 267) | func (*IntervalClock) NewTimer(time.Duration) clock.Timer {
    method AfterFunc (line 273) | func (*IntervalClock) AfterFunc(time.Duration, func()) clock.Timer {
    method NewTicker (line 279) | func (*IntervalClock) NewTicker(time.Duration) clock.Ticker {
    method Sleep (line 284) | func (*IntervalClock) Sleep(time.Duration) {
  type fakeTimer (line 291) | type fakeTimer struct
    method C (line 297) | func (f *fakeTimer) C() <-chan time.Time {
    method Stop (line 302) | func (f *fakeTimer) Stop() bool {
    method Reset (line 321) | func (f *fakeTimer) Reset(d time.Duration) bool {
  type fakeTicker (line 345) | type fakeTicker struct
    method C (line 349) | func (t *fakeTicker) C() <-chan time.Time {
    method Stop (line 353) | func (t *fakeTicker) Stop() {

FILE: internal/clock/testing/simple_interval_clock.go
  type SimpleIntervalClock (line 30) | type SimpleIntervalClock struct
    method Now (line 36) | func (i *SimpleIntervalClock) Now() time.Time {
    method Since (line 42) | func (i *SimpleIntervalClock) Since(ts time.Time) time.Duration {

FILE: internal/dbg/dbg.go
  function Stacks (line 26) | func Stacks(all bool) []byte {

FILE: internal/serialize/keyvalues.go
  type textWriter (line 30) | type textWriter interface
  function WithValues (line 37) | func WithValues(oldKV, newKV []interface{}) []interface{} {
  type Formatter (line 56) | type Formatter struct
    method FormatKVs (line 70) | func (f Formatter) FormatKVs(b *bytes.Buffer, kvs ...[]interface{}) {
    method formatAny (line 191) | func (f Formatter) formatAny(b *bytes.Buffer, v interface{}) {
  type AnyToStringFunc (line 60) | type AnyToStringFunc
  constant missingValue (line 62) | missingValue = "(MISSING)"
  function FormatKVs (line 64) | func FormatKVs(b *bytes.Buffer, kvs ...[]interface{}) {
  type obsoleteKV (line 169) | type obsoleteKV struct
  type interval (line 175) | type interval struct
  function findObsoleteEntry (line 180) | func findObsoleteEntry(entries []obsoleteKV, key string) int {
  function formatAsJSON (line 210) | func formatAsJSON(b *bytes.Buffer, v interface{}) {
  function StringerToString (line 226) | func StringerToString(s fmt.Stringer) (ret string) {
  function MarshalerToValue (line 238) | func MarshalerToValue(m logr.Marshaler) (ret interface{}) {
  function ErrorToString (line 250) | func ErrorToString(err error) (ret string) {
  function writeTextWriterValue (line 260) | func writeTextWriterValue(b *bytes.Buffer, v textWriter) {
  function writeStringValue (line 270) | func writeStringValue(b *bytes.Buffer, v string) {

FILE: internal/serialize/keyvalues_no_slog.go
  method KVFormat (line 31) | func (f Formatter) KVFormat(b *bytes.Buffer, k, v interface{}) string {

FILE: internal/serialize/keyvalues_slog.go
  method KVFormat (line 33) | func (f Formatter) KVFormat(b *bytes.Buffer, k, v interface{}) string {
  function generateJSON (line 123) | func generateJSON(b *bytes.Buffer, v interface{}) {

FILE: internal/serialize/keyvalues_test.go
  type point (line 31) | type point struct
    method String (line 37) | func (p point) String() string {
  type dummyStruct (line 41) | type dummyStruct struct
    method MarshalLog (line 46) | func (d *dummyStruct) MarshalLog() interface{} {
  type dummyStructWithStringMarshal (line 53) | type dummyStructWithStringMarshal struct
    method MarshalLog (line 58) | func (d *dummyStructWithStringMarshal) MarshalLog() interface{} {
  function TestKvListFormat (line 63) | func TestKvListFormat(t *testing.T) {

FILE: internal/severity/severity.go
  type Severity (line 25) | type Severity
  constant InfoLog (line 31) | InfoLog Severity = iota
  constant WarningLog (line 32) | WarningLog
  constant ErrorLog (line 33) | ErrorLog
  constant FatalLog (line 34) | FatalLog
  constant NumSeverity (line 35) | NumSeverity = 4
  constant Char (line 39) | Char = "IWEF"
  function ByName (line 50) | func ByName(s string) (Severity, bool) {

FILE: internal/sloghandler/sloghandler_slog.go
  function Handle (line 32) | func Handle(_ context.Context, record slog.Record, groups string, printW...
  function Attrs2KVList (line 80) | func Attrs2KVList(groups string, attrs []slog.Attr) []interface{} {
  function appendAttr (line 88) | func appendAttr(groups string, kvList []interface{}, attr slog.Attr) []i...

FILE: internal/test/mock.go
  type KMetadataMock (line 20) | type KMetadataMock struct
    method GetName (line 24) | func (m KMetadataMock) GetName() string {
    method GetNamespace (line 27) | func (m KMetadataMock) GetNamespace() string {
  type PtrKMetadataMock (line 31) | type PtrKMetadataMock struct
    method GetName (line 35) | func (m *PtrKMetadataMock) GetName() string {
    method GetNamespace (line 38) | func (m *PtrKMetadataMock) GetNamespace() string {

FILE: internal/test/require/require.go
  function NoError (line 21) | func NoError(tb testing.TB, err error) {

FILE: internal/verbosity/helper_test.go
  function enabledInHelper (line 19) | func enabledInHelper(vs *VState, l Level) bool {

FILE: internal/verbosity/verbosity.go
  function New (line 36) | func New() *VState {
  type Value (line 48) | type Value interface
  type VState (line 63) | type VState struct
    method V (line 53) | func (vs *VState) V() Value {
    method VModule (line 57) | func (vs *VState) VModule() Value {
    method set (line 224) | func (vs *VState) set(l Level, filter []modulePat, setFilter bool) {
    method Enabled (line 247) | func (vs *VState) Enabled(level Level, depth int) bool {
    method setV (line 287) | func (vs *VState) setV(pc uintptr) Level {
  type Level (line 83) | type Level
  type levelSpec (line 85) | type levelSpec struct
    method get (line 91) | func (l *levelSpec) get() Level {
    method set (line 96) | func (l *levelSpec) set(val Level) {
    method String (line 101) | func (l *levelSpec) String() string {
    method Get (line 107) | func (l *levelSpec) Get() interface{} {
    method Type (line 112) | func (l *levelSpec) Type() string {
    method Set (line 117) | func (l *levelSpec) Set(value string) error {
  type moduleSpec (line 129) | type moduleSpec struct
    method String (line 152) | func (m *moduleSpec) String() string {
    method Get (line 172) | func (m *moduleSpec) Get() interface{} {
    method Type (line 177) | func (m *moduleSpec) Type() string {
    method Set (line 185) | func (m *moduleSpec) Set(value string) error {
  type modulePat (line 136) | type modulePat struct
    method match (line 144) | func (m *modulePat) match(file string) bool {
  function isLiteral (line 218) | func isLiteral(pattern string) bool {

FILE: internal/verbosity/verbosity_test.go
  function TestV (line 26) | func TestV(t *testing.T) {
  function TestVmoduleOn (line 41) | func TestVmoduleOn(t *testing.T) {
  function testVmoduleGlob (line 84) | func testVmoduleGlob(pat string, match bool, t *testing.T) {
  function TestVmoduleGlob (line 95) | func TestVmoduleGlob(t *testing.T) {

FILE: k8s_references.go
  type ObjectRef (line 29) | type ObjectRef struct
    method String (line 34) | func (ref ObjectRef) String() string {
    method WriteText (line 46) | func (ref ObjectRef) WriteText(out *bytes.Buffer) {
    method writeUnquoted (line 52) | func (ref ObjectRef) writeUnquoted(out *bytes.Buffer) {
    method MarshalLog (line 62) | func (ref ObjectRef) MarshalLog() interface{} {
  type KMetadata (line 72) | type KMetadata interface
  function KObj (line 78) | func KObj(obj KMetadata) ObjectRef {
  function KRef (line 93) | func KRef(namespace, name string) ObjectRef {
  function KObjs (line 103) | func KObjs(arg interface{}) []ObjectRef {
  function KObjSlice (line 129) | func KObjSlice(arg interface{}) interface{} {
  type kobjSlice (line 133) | type kobjSlice struct
    method String (line 140) | func (ks kobjSlice) String() string {
    method MarshalLog (line 148) | func (ks kobjSlice) MarshalLog() interface{} {
    method process (line 156) | func (ks kobjSlice) process() (objs []interface{}, err string) {
    method WriteText (line 183) | func (ks kobjSlice) WriteText(out *bytes.Buffer) {

FILE: k8s_references_slog.go
  method LogValue (line 26) | func (ref ObjectRef) LogValue() slog.Value {
  method LogValue (line 35) | func (ks kobjSlice) LogValue() slog.Value {

FILE: klog.go
  type severityValue (line 137) | type severityValue struct
    method get (line 142) | func (s *severityValue) get() severity.Severity {
    method set (line 147) | func (s *severityValue) set(val severity.Severity) {
    method String (line 152) | func (s *severityValue) String() string {
    method Get (line 157) | func (s *severityValue) Get() interface{} {
    method Set (line 162) | func (s *severityValue) Set(value string) error {
  type OutputStats (line 179) | type OutputStats struct
    method Lines (line 185) | func (s *OutputStats) Lines() int64 {
    method Bytes (line 190) | func (s *OutputStats) Bytes() int64 {
  type Level (line 218) | type Level
    method get (line 221) | func (l *Level) get() Level {
    method set (line 226) | func (l *Level) set(val Level) {
    method String (line 231) | func (l *Level) String() string {
    method Get (line 236) | func (l *Level) Get() interface{} {
    method Set (line 241) | func (l *Level) Set(value string) error {
  type moduleSpec (line 253) | type moduleSpec struct
    method String (line 275) | func (m *moduleSpec) String() string {
    method serialize (line 282) | func (m *moduleSpec) serialize() string {
    method Get (line 295) | func (m *moduleSpec) Get() interface{} {
    method Set (line 303) | func (m *moduleSpec) Set(value string) error {
  type modulePat (line 259) | type modulePat struct
    method match (line 267) | func (m *modulePat) match(file string) bool {
  function parseModuleSpec (line 314) | func parseModuleSpec(value string) ([]modulePat, error) {
  function isLiteral (line 344) | func isLiteral(pattern string) bool {
  type traceLocation (line 349) | type traceLocation struct
    method isSet (line 356) | func (t *traceLocation) isSet() bool {
    method match (line 363) | func (t *traceLocation) match(file string, line int) bool {
    method String (line 373) | func (t *traceLocation) String() string {
    method Get (line 382) | func (t *traceLocation) Get() interface{} {
    method Set (line 391) | func (t *traceLocation) Set(value string) error {
  function init (line 426) | func init() {
  function InitFlags (line 463) | func InitFlags(flagset *flag.FlagSet) {
  function Flush (line 474) | func Flush() {
  type settings (line 479) | type settings struct
    method deepCopy (line 552) | func (s settings) deepCopy() settings {
  type loggingT (line 567) | type loggingT struct
    method setVState (line 587) | func (l *loggingT) setVState(verbosity Level, filter []modulePat, setF...
    method header (line 676) | func (l *loggingT) header(s severity.Severity, depth int) (*buffer.Buf...
    method formatHeader (line 696) | func (l *loggingT) formatHeader(s severity.Severity, file string, line...
    method println (line 705) | func (l *loggingT) println(s severity.Severity, logger *logWriter, fil...
    method printlnDepth (line 709) | func (l *loggingT) printlnDepth(s severity.Severity, logger *logWriter...
    method print (line 729) | func (l *loggingT) print(s severity.Severity, logger *logWriter, filte...
    method printDepth (line 733) | func (l *loggingT) printDepth(s severity.Severity, logger *logWriter, ...
    method printWithInfos (line 742) | func (l *loggingT) printWithInfos(buf *buffer.Buffer, file string, lin...
    method printf (line 760) | func (l *loggingT) printf(s severity.Severity, logger *logWriter, filt...
    method printfDepth (line 764) | func (l *loggingT) printfDepth(s severity.Severity, logger *logWriter,...
    method printWithFileLine (line 790) | func (l *loggingT) printWithFileLine(s severity.Severity, logger *logW...
    method errorS (line 810) | func (l *loggingT) errorS(err error, logger *logWriter, filter LogFilt...
    method infoS (line 822) | func (l *loggingT) infoS(logger *logWriter, filter LogFilter, depth in...
    method printS (line 835) | func (l *loggingT) printS(err error, s severity.Severity, depth int, m...
    method output (line 885) | func (l *loggingT) output(s severity.Severity, logger *logWriter, buf ...
    method exit (line 1022) | func (l *loggingT) exit(err error) {
    method createFiles (line 1122) | func (l *loggingT) createFiles(sev severity.Severity) error {
    method lockAndFlushAll (line 1236) | func (l *loggingT) lockAndFlushAll() {
    method flushAll (line 1248) | func (l *loggingT) flushAll() fileArray {
    method syncAll (line 1272) | func (l *loggingT) syncAll(needToSync fileArray) {
    method setV (line 1346) | func (l *loggingT) setV(pc uintptr) Level {
  function CaptureState (line 609) | func CaptureState() State {
  type State (line 622) | type State interface
  type state (line 627) | type state struct
    method Restore (line 634) | func (s *state) Restore() {
  function SetOutput (line 857) | func SetOutput(w io.Writer) {
  function SetOutputBySeverity (line 866) | func SetOutputBySeverity(name string, w io.Writer) {
  function LogToStderr (line 877) | func LogToStderr(stderr bool) {
  type syncBuffer (line 1038) | type syncBuffer struct
    method Write (line 1061) | func (sb *syncBuffer) Write(p []byte) (n int, err error) {
    method rotateFile (line 1078) | func (sb *syncBuffer) rotateFile(now time.Time, startup bool) error {
  function CalculateMaxSize (line 1048) | func CalculateMaxSize() uint64 {
  constant bufferSize (line 1118) | bufferSize = 256 * 1024
  constant flushInterval (line 1145) | flushInterval = 5 * time.Second
  type flushDaemon (line 1148) | type flushDaemon struct
    method run (line 1170) | func (f *flushDaemon) run(interval time.Duration) {
    method stop (line 1199) | func (f *flushDaemon) stop() {
    method isRunning (line 1215) | func (f *flushDaemon) isRunning() bool {
  function newFlushDaemon (line 1158) | func newFlushDaemon(flush func(), tickClock clock.Clock) *flushDaemon {
  function StopFlushDaemon (line 1224) | func StopFlushDaemon() {
  function StartFlushDaemon (line 1230) | func StartFlushDaemon(interval time.Duration) {
  type fileArray (line 1266) | type fileArray struct
  function CopyStandardLogTo (line 1286) | func CopyStandardLogTo(name string) {
  function NewStandardLogger (line 1302) | func NewStandardLogger(name string) *stdLog.Logger {
  type logBridge (line 1312) | type logBridge
    method Write (line 1316) | func (lb logBridge) Write(b []byte) (n int, err error) {
  type Verbose (line 1366) | type Verbose struct
    method Enabled (line 1442) | func (v Verbose) Enabled() bool {
    method Info (line 1448) | func (v Verbose) Info(args ...interface{}) {
    method InfoDepth (line 1456) | func (v Verbose) InfoDepth(depth int, args ...interface{}) {
    method Infoln (line 1464) | func (v Verbose) Infoln(args ...interface{}) {
    method InfolnDepth (line 1472) | func (v Verbose) InfolnDepth(depth int, args ...interface{}) {
    method Infof (line 1480) | func (v Verbose) Infof(format string, args ...interface{}) {
    method InfofDepth (line 1488) | func (v Verbose) InfofDepth(depth int, format string, args ...interfac...
    method InfoS (line 1496) | func (v Verbose) InfoS(msg string, keysAndValues ...interface{}) {
    method InfoSDepth (line 1510) | func (v Verbose) InfoSDepth(depth int, msg string, keysAndValues ...in...
    method Error (line 1517) | func (v Verbose) Error(err error, msg string, args ...interface{}) {
    method ErrorS (line 1525) | func (v Verbose) ErrorS(err error, msg string, keysAndValues ...interf...
  function newVerbose (line 1371) | func newVerbose(level Level, b bool) Verbose {
  function V (line 1398) | func V(level Level) Verbose {
  function VDepth (line 1405) | func VDepth(depth int, level Level) Verbose {
  function InfoSDepth (line 1504) | func InfoSDepth(depth int, msg string, keysAndValues ...interface{}) {
  function Info (line 1533) | func Info(args ...interface{}) {
  function InfoDepth (line 1539) | func InfoDepth(depth int, args ...interface{}) {
  function Infoln (line 1545) | func Infoln(args ...interface{}) {
  function InfolnDepth (line 1551) | func InfolnDepth(depth int, args ...interface{}) {
  function Infof (line 1557) | func Infof(format string, args ...interface{}) {
  function InfofDepth (line 1563) | func InfofDepth(depth int, format string, args ...interface{}) {
  function InfoS (line 1575) | func InfoS(msg string, keysAndValues ...interface{}) {
  function Warning (line 1581) | func Warning(args ...interface{}) {
  function WarningDepth (line 1587) | func WarningDepth(depth int, args ...interface{}) {
  function Warningln (line 1593) | func Warningln(args ...interface{}) {
  function WarninglnDepth (line 1599) | func WarninglnDepth(depth int, args ...interface{}) {
  function Warningf (line 1605) | func Warningf(format string, args ...interface{}) {
  function WarningfDepth (line 1611) | func WarningfDepth(depth int, format string, args ...interface{}) {
  function Error (line 1617) | func Error(args ...interface{}) {
  function ErrorDepth (line 1623) | func ErrorDepth(depth int, args ...interface{}) {
  function Errorln (line 1629) | func Errorln(args ...interface{}) {
  function ErrorlnDepth (line 1635) | func ErrorlnDepth(depth int, args ...interface{}) {
  function Errorf (line 1641) | func Errorf(format string, args ...interface{}) {
  function ErrorfDepth (line 1647) | func ErrorfDepth(depth int, format string, args ...interface{}) {
  function ErrorS (line 1660) | func ErrorS(err error, msg string, keysAndValues ...interface{}) {
  function ErrorSDepth (line 1666) | func ErrorSDepth(depth int, err error, msg string, keysAndValues ...inte...
  function Fatal (line 1684) | func Fatal(args ...interface{}) {
  function FatalDepth (line 1690) | func FatalDepth(depth int, args ...interface{}) {
  function Fatalln (line 1697) | func Fatalln(args ...interface{}) {
  function FatallnDepth (line 1703) | func FatallnDepth(depth int, args ...interface{}) {
  function Fatalf (line 1710) | func Fatalf(format string, args ...interface{}) {
  function FatalfDepth (line 1716) | func FatalfDepth(depth int, format string, args ...interface{}) {
  function Exit (line 1726) | func Exit(args ...interface{}) {
  function ExitDepth (line 1733) | func ExitDepth(depth int, args ...interface{}) {
  function Exitln (line 1739) | func Exitln(args ...interface{}) {
  function ExitlnDepth (line 1746) | func ExitlnDepth(depth int, args ...interface{}) {
  function Exitf (line 1753) | func Exitf(format string, args ...interface{}) {
  function ExitfDepth (line 1760) | func ExitfDepth(depth int, format string, args ...interface{}) {
  type LogFilter (line 1767) | type LogFilter interface
  function SetLogFilter (line 1777) | func SetLogFilter(filter LogFilter) {

FILE: klog_file.go
  function createLogDirs (line 37) | func createLogDirs() {
  function init (line 52) | func init() {
  function shortHostname (line 60) | func shortHostname(hostname string) string {
  function logName (line 69) | func logName(tag string, t time.Time) (name, link string) {
  function create (line 93) | func create(tag string, t time.Time, startup bool) (f *os.File, filename...
  function openOrCreate (line 123) | func openOrCreate(name string, startup bool) (*os.File, error) {

FILE: klog_file_others.go
  function getUserName (line 10) | func getUserName() string {

FILE: klog_file_windows.go
  function getUserName (line 11) | func getUserName() string {

FILE: klog_test.go
  function TestShortHostname (line 51) | func TestShortHostname(t *testing.T) {
  type flushBuffer (line 64) | type flushBuffer struct
    method Flush (line 68) | func (f *flushBuffer) Flush() error {
    method Sync (line 72) | func (f *flushBuffer) Sync() error {
  method swap (line 77) | func (l *loggingT) swap(writers [severity.NumSeverity]io.Writer) (old [s...
  method newBuffers (line 86) | func (l *loggingT) newBuffers() [severity.NumSeverity]io.Writer {
  function contents (line 91) | func contents(s severity.Severity) string {
  function contains (line 96) | func contains(s severity.Severity, str string) bool {
  function setFlags (line 101) | func setFlags() {
  function TestInfo (line 107) | func TestInfo(t *testing.T) {
  function TestInfoDepth (line 120) | func TestInfoDepth(t *testing.T) {
  function init (line 165) | func init() {
  function TestCopyStandardLogToPanic (line 170) | func TestCopyStandardLogToPanic(t *testing.T) {
  function TestStandardLog (line 180) | func TestStandardLog(t *testing.T) {
  function TestHeader (line 194) | func TestHeader(t *testing.T) {
  function TestHeaderWithDir (line 218) | func TestHeaderWithDir(t *testing.T) {
  function TestError (line 238) | func TestError(t *testing.T) {
  function TestErrorWithOneOutput (line 261) | func TestErrorWithOneOutput(t *testing.T) {
  function TestWarning (line 285) | func TestWarning(t *testing.T) {
  function TestWarningWithOneOutput (line 305) | func TestWarningWithOneOutput(t *testing.T) {
  function TestV (line 324) | func TestV(t *testing.T) {
  function TestVmoduleOn (line 339) | func TestVmoduleOn(t *testing.T) {
  function TestVmoduleOff (line 363) | func TestVmoduleOff(t *testing.T) {
  function TestSetOutputDataRace (line 379) | func TestSetOutputDataRace(*testing.T) {
  function TestLogToOutput (line 420) | func TestLogToOutput(t *testing.T) {
  function testVmoduleGlob (line 455) | func testVmoduleGlob(pat string, match bool, t *testing.T) {
  function TestVmoduleGlob (line 466) | func TestVmoduleGlob(t *testing.T) {
  function TestRollover (line 472) | func TestRollover(t *testing.T) {
  function TestOpenAppendOnStart (line 516) | func TestOpenAppendOnStart(t *testing.T) {
  function TestLogBacktraceAt (line 590) | func TestLogBacktraceAt(t *testing.T) {
  function BenchmarkHeader (line 627) | func BenchmarkHeader(b *testing.B) {
  function BenchmarkHeaderWithDir (line 634) | func BenchmarkHeaderWithDir(b *testing.B) {
  function BenchmarkV (line 646) | func BenchmarkV(b *testing.B) {
  function BenchmarkKRef (line 654) | func BenchmarkKRef(b *testing.B) {
  function BenchmarkKObj (line 662) | func BenchmarkKObj(b *testing.B) {
  function BenchmarkKObjs (line 680) | func BenchmarkKObjs(b *testing.B) {
  function BenchmarkKObjSlice (line 708) | func BenchmarkKObjSlice(b *testing.B) {
  function BenchmarkScalars (line 737) | func BenchmarkScalars(b *testing.B) {
  function BenchmarkScalarsWithLogger (line 757) | func BenchmarkScalarsWithLogger(b *testing.B) {
  function BenchmarkKObjSliceWithLogger (line 780) | func BenchmarkKObjSliceWithLogger(b *testing.B) {
  function BenchmarkLogs (line 800) | func BenchmarkLogs(b *testing.B) {
  function BenchmarkFlush (line 836) | func BenchmarkFlush(b *testing.B) {
  function TestFileSizeCheck (line 873) | func TestFileSizeCheck(t *testing.T) {
  function TestInitFlags (line 920) | func TestInitFlags(t *testing.T) {
  function TestCommandLine (line 939) | func TestCommandLine(t *testing.T) {
  function TestInfoObjectRef (line 985) | func TestInfoObjectRef(t *testing.T) {
  function TestKObj (line 1028) | func TestKObj(t *testing.T) {
  function TestKRef (line 1080) | func TestKRef(t *testing.T) {
  function TestInfoS (line 1115) | func TestInfoS(t *testing.T) {
  function TestVInfoS (line 1172) | func TestVInfoS(t *testing.T) {
  function TestErrorS (line 1253) | func TestErrorS(t *testing.T) {
  function createTestValueOfLoggingT (line 1297) | func createTestValueOfLoggingT() *loggingT {
  function createTestValueOfModulePat (line 1311) | func createTestValueOfModulePat(p string, li bool, le Level) modulePat {
  function compareModuleSpec (line 1319) | func compareModuleSpec(a, b moduleSpec) bool {
  function TestSetVState (line 1333) | func TestSetVState(t *testing.T) {
  type sampleLogFilter (line 1362) | type sampleLogFilter struct
    method Filter (line 1364) | func (f *sampleLogFilter) Filter(args []interface{}) []interface{} {
    method FilterF (line 1374) | func (f *sampleLogFilter) FilterF(format string, args []interface{}) (...
    method FilterS (line 1378) | func (f *sampleLogFilter) FilterS(msg string, keysAndValues []interfac...
  function TestLogFilter (line 1382) | func TestLogFilter(t *testing.T) {
  function TestInfoWithLogr (line 1529) | func TestInfoWithLogr(t *testing.T) {
  function TestInfoSWithLogr (line 1565) | func TestInfoSWithLogr(t *testing.T) {
  function TestErrorSWithLogr (line 1606) | func TestErrorSWithLogr(t *testing.T) {
  function TestCallDepthLogr (line 1674) | func TestCallDepthLogr(t *testing.T) {
  function TestCallDepthLogrInfoS (line 1737) | func TestCallDepthLogrInfoS(t *testing.T) {
  function TestCallDepthLogrErrorS (line 1760) | func TestCallDepthLogrErrorS(t *testing.T) {
  function TestCallDepthLogrGoLog (line 1783) | func TestCallDepthLogrGoLog(t *testing.T) {
  function TestCallDepthTestLogr (line 1809) | func TestCallDepthTestLogr(t *testing.T) {
  type testLogr (line 1842) | type testLogr struct
    method reset (line 1854) | func (l *testLogr) reset() {
    method Info (line 1860) | func (l *testLogr) Info(_ int, msg string, keysAndValues ...interface{...
    method Error (line 1870) | func (l *testLogr) Error(err error, msg string, keysAndValues ...inter...
    method Init (line 1881) | func (l *testLogr) Init(logr.RuntimeInfo)                  {}
    method Enabled (line 1882) | func (l *testLogr) Enabled(int) bool                       { return tr...
    method V (line 1883) | func (l *testLogr) V(int) logr.Logger                      { panic("no...
    method WithName (line 1884) | func (l *testLogr) WithName(string) logr.LogSink           { panic("no...
    method WithValues (line 1885) | func (l *testLogr) WithValues(...interface{}) logr.LogSink { panic("no...
    method WithCallDepth (line 1886) | func (l *testLogr) WithCallDepth(int) logr.LogSink         { return l }
  type testLogrEntry (line 1847) | type testLogrEntry struct
  type callDepthTestLogr (line 1891) | type callDepthTestLogr struct
    method resetCallDepth (line 1896) | func (l *callDepthTestLogr) resetCallDepth() {
    method WithCallDepth (line 1902) | func (l *callDepthTestLogr) WithCallDepth(depth int) logr.LogSink {
    method Info (line 1912) | func (l *callDepthTestLogr) Info(_ int, msg string, keysAndValues ...i...
    method Error (line 1925) | func (l *callDepthTestLogr) Error(err error, msg string, keysAndValues...
  function checkLogrEntryCorrectCaller (line 1942) | func checkLogrEntryCorrectCaller(t *testing.T, wantFile string, wantLine...
  constant KlogPrefix (line 1974) | KlogPrefix string = "klog"
  function TestKlogFlagPrefix (line 1977) | func TestKlogFlagPrefix(t *testing.T) {
  function TestKObjs (line 1989) | func TestKObjs(t *testing.T) {
  type structWithLock (line 2068) | type structWithLock struct
    method addWithoutDefer (line 2087) | func (s *structWithLock) addWithoutDefer() {
    method addWithDefer (line 2093) | func (s *structWithLock) addWithDefer() {
  function BenchmarkWithoutDeferUnLock (line 2073) | func BenchmarkWithoutDeferUnLock(b *testing.B) {
  function BenchmarkWithDeferUnLock (line 2080) | func BenchmarkWithDeferUnLock(b *testing.B) {
  function TestFlushDaemon (line 2099) | func TestFlushDaemon(t *testing.T) {
  function TestStopFlushDaemon (line 2149) | func TestStopFlushDaemon(t *testing.T) {
  function TestCaptureState (line 2162) | func TestCaptureState(t *testing.T) {
  function TestSettingsDeepCopy (line 2246) | func TestSettingsDeepCopy(t *testing.T) {

FILE: klog_wrappers_test.go
  function myInfoS (line 21) | func myInfoS(msg string, keyAndValues ...interface{}) {
  function myErrorS (line 25) | func myErrorS(err error, msg string, keyAndValues ...interface{}) {

FILE: klogr.go
  constant nameKey (line 27) | nameKey = "logger"
  function NewKlogr (line 33) | func NewKlogr() Logger {
  type klogger (line 39) | type klogger struct
    method Init (line 51) | func (l *klogger) Init(info logr.RuntimeInfo) {
    method Info (line 55) | func (l *klogger) Info(level int, msg string, kvList ...interface{}) {
    method Enabled (line 61) | func (l *klogger) Enabled(level int) bool {
    method Error (line 65) | func (l *klogger) Error(err error, msg string, kvList ...interface{}) {
    method WithName (line 73) | func (l klogger) WithName(name string) logr.LogSink {
    method WithValues (line 94) | func (l klogger) WithValues(kvList ...interface{}) logr.LogSink {
    method WithCallDepth (line 99) | func (l klogger) WithCallDepth(depth int) logr.LogSink {

FILE: klogr/calldepth-test/call_depth_helper_test.go
  function myInfo (line 10) | func myInfo(l logr.Logger, msg string) {
  function myInfo2 (line 14) | func myInfo2(l logr.Logger, msg string) {

FILE: klogr/calldepth-test/call_depth_main_test.go
  function TestCallDepth (line 20) | func TestCallDepth(t *testing.T) {

FILE: klogr/klogr.go
  constant nameKey (line 20) | nameKey = "logger"
  type Option (line 24) | type Option
  type Format (line 27) | type Format
  constant FormatSerialize (line 32) | FormatSerialize Format = "Serialize"
  constant FormatKlog (line 37) | FormatKlog Format = "Klog"
  function WithFormat (line 41) | func WithFormat(format Format) Option {
  function New (line 51) | func New() logr.Logger {
  function NewWithOptions (line 60) | func NewWithOptions(options ...Option) logr.Logger {
  type klogger (line 72) | type klogger struct
    method Init (line 85) | func (l *klogger) Init(info logr.RuntimeInfo) {
    method Info (line 137) | func (l *klogger) Info(level int, msg string, kvList ...interface{}) {
    method Enabled (line 150) | func (l *klogger) Enabled(level int) bool {
    method Error (line 154) | func (l *klogger) Error(err error, msg string, kvList ...interface{}) {
    method WithName (line 175) | func (l klogger) WithName(name string) logr.LogSink {
    method WithValues (line 197) | func (l klogger) WithValues(kvList ...interface{}) logr.LogSink {
    method WithCallDepth (line 202) | func (l klogger) WithCallDepth(depth int) logr.LogSink {
  function flatten (line 89) | func flatten(kvList ...interface{}) string {
  function pretty (line 122) | func pretty(value interface{}) string {

FILE: klogr/klogr_test.go
  constant formatDefault (line 18) | formatDefault = "Default"
  constant formatNew (line 19) | formatNew     = "New"
  function testOutput (line 22) | func testOutput(t *testing.T, format string) {
  function TestOutput (line 211) | func TestOutput(t *testing.T) {
  type customErrorJSON (line 228) | type customErrorJSON struct
    method Error (line 232) | func (e *customErrorJSON) Error() string {
    method MarshalJSON (line 236) | func (e *customErrorJSON) MarshalJSON() ([]byte, error) {

FILE: klogr/output_test.go
  function TestKlogrOutput (line 30) | func TestKlogrOutput(t *testing.T) {

FILE: klogr_helper_test.go
  function testVerbosity (line 25) | func testVerbosity(t *testing.T, logger klog.Logger) {

FILE: klogr_slog.go
  method Handle (line 36) | func (l *klogger) Handle(ctx context.Context, record slog.Record) error {
  function slogOutput (line 50) | func slogOutput(file string, line int, now time.Time, err error, s sever...
  method WithAttrs (line 85) | func (l *klogger) WithAttrs(attrs []slog.Attr) logr.SlogSink {
  method WithGroup (line 91) | func (l *klogger) WithGroup(name string) logr.SlogSink {

FILE: klogr_slog_test.go
  type coordinates (line 38) | type coordinates struct
    method LogValue (line 42) | func (c coordinates) LogValue() slog.Value {
  function ExampleBackground_slog (line 46) | func ExampleBackground_slog() {

FILE: klogr_test.go
  function TestVerbosity (line 28) | func TestVerbosity(t *testing.T) {

FILE: ktesting/contextual_test.go
  function TestContextual (line 18) | func TestContextual(t *testing.T) {
  function doSomething (line 51) | func doSomething(ctx context.Context) {
  function doSomeMore (line 60) | func doSomeMore(ctx context.Context) {

FILE: ktesting/example/example_test.go
  function TestKlogr (line 19) | func TestKlogr(t *testing.T) {
  type pair (line 24) | type pair struct
    method String (line 28) | func (p pair) String() string {
  type err (line 34) | type err struct
    method Error (line 38) | func (e err) Error() string {
  function exampleOutput (line 44) | func exampleOutput(logger klog.Logger) {

FILE: ktesting/example_test.go
  function ExampleUnderlier (line 28) | func ExampleUnderlier() {
  function ExampleNewLogger (line 95) | func ExampleNewLogger() {
  function ExampleConfig_Verbosity (line 116) | func ExampleConfig_Verbosity() {

FILE: ktesting/helper_test.go
  function callDepthHelper (line 13) | func callDepthHelper(logger klog.Logger, msg string) {

FILE: ktesting/init/init.go
  function init (line 28) | func init() {

FILE: ktesting/main_test.go
  function TestMain (line 16) | func TestMain(m *testing.M) {

FILE: ktesting/options.go
  type Config (line 32) | type Config struct
    method Verbosity (line 40) | func (c *Config) Verbosity() flag.Value {
    method VModule (line 47) | func (c *Config) VModule() flag.Value {
    method AddFlags (line 129) | func (c *Config) AddFlags(fs *flag.FlagSet) {
  type ConfigOption (line 52) | type ConfigOption
  type configOptions (line 54) | type configOptions struct
  function AnyToString (line 65) | func AnyToString(anyToString func(value interface{}) string) ConfigOption {
  function VerbosityFlagName (line 72) | func VerbosityFlagName(name string) ConfigOption {
  function VModuleFlagName (line 80) | func VModuleFlagName(name string) ConfigOption {
  function Verbosity (line 92) | func Verbosity(level int) ConfigOption {
  function BufferLogs (line 102) | func BufferLogs(enabled bool) ConfigOption {
  function NewConfig (line 110) | func NewConfig(opts ...ConfigOption) *Config {

FILE: ktesting/setup.go
  function NewTestContext (line 33) | func NewTestContext(tl TL) (logr.Logger, context.Context) {

FILE: ktesting/testinglogger.go
  type TL (line 56) | type TL interface
  type NopTL (line 63) | type NopTL struct
    method Helper (line 65) | func (n NopTL) Helper()            {}
    method Log (line 66) | func (n NopTL) Log(...interface{}) {}
  type BufferTL (line 71) | type BufferTL struct
    method Helper (line 75) | func (n *BufferTL) Helper() {}
    method Log (line 76) | func (n *BufferTL) Log(args ...interface{}) {
  function NewLogger (line 92) | func NewLogger(t TL, c *Config) logr.Logger {
  type Buffer (line 119) | type Buffer interface
  type Log (line 129) | type Log
    method DeepCopy (line 133) | func (l Log) DeepCopy() Log {
  type LogEntry (line 140) | type LogEntry struct
  type LogType (line 172) | type LogType
  constant LogError (line 176) | LogError = LogType("ERROR")
  constant LogInfo (line 179) | LogInfo = LogType("INFO")
  type Underlier (line 184) | type Underlier interface
  type logBuffer (line 193) | type logBuffer struct
    method String (line 199) | func (b *logBuffer) String() string {
    method Data (line 205) | func (b *logBuffer) Data() Log {
  type tloggerShared (line 213) | type tloggerShared struct
    method stop (line 246) | func (ls *tloggerShared) stop() {
  constant stopGracePeriod (line 244) | stopGracePeriod = 10 * time.Second
  type tlogger (line 254) | type tlogger struct
    method fallbackLogger (line 262) | func (l tlogger) fallbackLogger() logr.Logger {
    method Init (line 281) | func (l tlogger) Init(info logr.RuntimeInfo) {
    method GetCallStackHelper (line 285) | func (l tlogger) GetCallStackHelper() func() {
    method Info (line 295) | func (l tlogger) Info(level int, msg string, kvList ...interface{}) {
    method Enabled (line 309) | func (l tlogger) Enabled(level int) bool {
    method Error (line 313) | func (l tlogger) Error(err error, msg string, kvList ...interface{}) {
    method log (line 331) | func (l tlogger) log(what LogType, msg string, level int, buf *buffer....
    method WithName (line 384) | func (l tlogger) WithName(name string) logr.LogSink {
    method WithValues (line 392) | func (l tlogger) WithValues(kvList ...interface{}) logr.LogSink {
    method GetUnderlying (line 397) | func (l tlogger) GetUnderlying() TL {
    method GetBuffer (line 401) | func (l tlogger) GetBuffer() Buffer {

FILE: ktesting/testinglogger_test.go
  function TestInfo (line 30) | func TestInfo(t *testing.T) {
  function TestCallDepthOutput (line 142) | func TestCallDepthOutput(t *testing.T) {
  function TestCallDepthVerify (line 154) | func TestCallDepthVerify(t *testing.T) {
  type logToBuf (line 173) | type logToBuf struct
    method Helper (line 178) | func (l *logToBuf) Helper() {
    method Log (line 181) | func (l *logToBuf) Log(args ...interface{}) {
  function TestStop (line 191) | func TestStop(t *testing.T) {

FILE: output_test.go
  function TestKlogOutput (line 32) | func TestKlogOutput(t *testing.T) {
  function BenchmarkKlogOutput (line 37) | func BenchmarkKlogOutput(b *testing.B) {
  function TestKlogrOutput (line 49) | func TestKlogrOutput(t *testing.T) {

FILE: safeptr.go
  function SafePtr (line 29) | func SafePtr[T any](p *T) any {

FILE: safeptr_test.go
  function TestSafePtr (line 28) | func TestSafePtr(t *testing.T) {

FILE: stderr_threshold_test.go
  function TestStderrThresholdWithLogToStderr (line 34) | func TestStderrThresholdWithLogToStderr(t *testing.T) {
  function TestAlsologtostderrthreshold (line 167) | func TestAlsologtostderrthreshold(t *testing.T) {
  function TestNewFlagParsing (line 288) | func TestNewFlagParsing(t *testing.T) {

FILE: test/output.go
  function InitKlog (line 47) | func InitKlog(tb testing.TB) *flag.FlagSet {
  type OutputConfig (line 71) | type OutputConfig struct
  type testcase (line 98) | type testcase struct
  function printWithLogger (line 456) | func printWithLogger(logger logr.Logger, test testcase) {
  function initPrintWithKlog (line 487) | func initPrintWithKlog(tb testing.TB, test testcase) {
  function printWithKlog (line 505) | func printWithKlog(test testcase) {
  function Output (line 557) | func Output(t *testing.T, config OutputConfig) {
  function Benchmark (line 877) | func Benchmark(b *testing.B, config OutputConfig) {
  function setLogger (line 915) | func setLogger(logger logr.Logger) bool {
  function copySlice (line 926) | func copySlice(in []interface{}) []interface{} {
  type kmeta (line 930) | type kmeta struct
    method GetName (line 934) | func (k kmeta) GetName() string {
    method GetNamespace (line 938) | func (k kmeta) GetNamespace() string {
  type customErrorJSON (line 944) | type customErrorJSON struct
    method Error (line 951) | func (e *customErrorJSON) Error() string {
    method MarshalJSON (line 955) | func (e *customErrorJSON) MarshalJSON() ([]byte, error) {
  type stringer (line 959) | type stringer struct
    method String (line 964) | func (s *stringer) String() string {
  type faultyStringer (line 970) | type faultyStringer struct
    method String (line 973) | func (f faultyStringer) String() string {
  type faultyMarshaler (line 979) | type faultyMarshaler struct
    method MarshalLog (line 982) | func (f faultyMarshaler) MarshalLog() interface{} {
  type recursiveMarshaler (line 988) | type recursiveMarshaler struct
    method MarshalLog (line 991) | func (r recursiveMarshaler) MarshalLog() interface{} {
  type faultyError (line 997) | type faultyError struct
    method Error (line 1000) | func (f faultyError) Error() string {
  type typeMeta (line 1008) | type typeMeta struct
    method String (line 1012) | func (t typeMeta) String() string {
    method MarshalLog (line 1016) | func (t typeMeta) MarshalLog() interface{} {
  type myConfig (line 1020) | type myConfig struct
  type myList (line 1030) | type myList struct
  function newCyclicList (line 1035) | func newCyclicList() *myList {
  type SpanID (line 1043) | type SpanID
    method MarshalJSON (line 1050) | func (s SpanID) MarshalJSON() ([]byte, error) {
    method String (line 1054) | func (s SpanID) String() string {
  function spanIDFromHex (line 1058) | func spanIDFromHex(str string) SpanID {
  type TraceID (line 1074) | type TraceID
    method MarshalJSON (line 1081) | func (s TraceID) MarshalJSON() ([]byte, error) {
    method String (line 1085) | func (s TraceID) String() string {
  function traceIDFromHex (line 1089) | func traceIDFromHex(str string) TraceID {

FILE: test/output_helper.go
  function loggerHelper (line 25) | func loggerHelper(logger logr.Logger, msg string, kv []interface{}) {
  function klogHelper (line 30) | func klogHelper(level klog.Level, msg string, kv []interface{}) {

FILE: test/zapr.go
  function ZaprOutputMappingDirect (line 21) | func ZaprOutputMappingDirect() map[string]string {
  function ZaprOutputMappingIndirect (line 302) | func ZaprOutputMappingIndirect() map[string]string {

FILE: textlogger/example_test.go
  function ExampleConfig_Verbosity (line 29) | func ExampleConfig_Verbosity() {

FILE: textlogger/options.go
  type Config (line 34) | type Config struct
    method Verbosity (line 42) | func (c *Config) Verbosity() flag.Value {
    method VModule (line 49) | func (c *Config) VModule() flag.Value {
    method AddFlags (line 169) | func (c *Config) AddFlags(fs *flag.FlagSet) {
  type ConfigOption (line 54) | type ConfigOption
  type configOptions (line 56) | type configOptions struct
  function VerbosityFlagName (line 67) | func VerbosityFlagName(name string) ConfigOption {
  function VModuleFlagName (line 76) | func VModuleFlagName(name string) ConfigOption {
  function Verbosity (line 85) | func Verbosity(level int) ConfigOption {
  function Output (line 92) | func Output(output io.Writer) ConfigOption {
  function FixedTime (line 104) | func FixedTime(ts time.Time) ConfigOption {
  function WithHeader (line 120) | func WithHeader(enabled bool) ConfigOption {
  function Backtrace (line 135) | func Backtrace(unwind func(skip int) (filename string, line int)) Config...
  function NewConfig (line 143) | func NewConfig(opts ...ConfigOption) *Config {

FILE: textlogger/output_test.go
  function newLogger (line 30) | func newLogger(out io.Writer, v int, vmodule string) logr.Logger {
  function TestTextloggerOutput (line 46) | func TestTextloggerOutput(t *testing.T) {
  function BenchmarkTextloggerOutput (line 56) | func BenchmarkTextloggerOutput(b *testing.B) {

FILE: textlogger/textlogger.go
  constant nameKey (line 45) | nameKey = "logger"
  function NewLogger (line 52) | func NewLogger(c *Config) logr.Logger {
  type tlogger (line 59) | type tlogger struct
    method Init (line 72) | func (l *tlogger) Init(info logr.RuntimeInfo) {
    method WithCallDepth (line 76) | func (l *tlogger) WithCallDepth(depth int) logr.LogSink {
    method Enabled (line 82) | func (l *tlogger) Enabled(level int) bool {
    method Info (line 86) | func (l *tlogger) Info(_ int, msg string, kvList ...interface{}) {
    method Error (line 90) | func (l *tlogger) Error(err error, msg string, kvList ...interface{}) {
    method print (line 94) | func (l *tlogger) print(err error, s severity.Severity, msg string, kv...
    method printWithInfos (line 122) | func (l *tlogger) printWithInfos(file string, line int, now time.Time,...
    method WriteKlogBuffer (line 154) | func (l *tlogger) WriteKlogBuffer(data []byte) {
    method WithName (line 161) | func (l *tlogger) WithName(name string) logr.LogSink {
    method WithValues (line 183) | func (l *tlogger) WithValues(kvList ...interface{}) logr.LogSink {
  function runtimeBacktrace (line 114) | func runtimeBacktrace(skip int) (string, int) {
  type KlogBufferWriter (line 190) | type KlogBufferWriter interface

FILE: textlogger/textlogger_slog.go
  method Handle (line 32) | func (l *tlogger) Handle(ctx context.Context, record slog.Record) error {
  method WithAttrs (line 36) | func (l *tlogger) WithAttrs(attrs []slog.Attr) logr.SlogSink {
  method WithGroup (line 42) | func (l *tlogger) WithGroup(name string) logr.SlogSink {

FILE: textlogger/textlogger_slog_test.go
  type coordinates (line 35) | type coordinates struct
    method LogValue (line 39) | func (c coordinates) LogValue() slog.Value {
  function ExampleNewLogger_slog (line 43) | func ExampleNewLogger_slog() {

FILE: textlogger/textlogger_test.go
  type coordinatesMarshaler (line 34) | type coordinatesMarshaler struct
    method MarshalLog (line 38) | func (c coordinatesMarshaler) MarshalLog() interface{} {
  type variables (line 42) | type variables struct
  function ExampleNewLogger (line 46) | func ExampleNewLogger() {
  function someHelper (line 77) | func someHelper(logger klog.Logger, msg string) {
  function ExampleBacktrace (line 81) | func ExampleBacktrace() {
  function ExampleWithHeader (line 114) | func ExampleWithHeader() {
Condensed preview — 107 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (497K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 338,
    "preview": "---\nname: Bug report\nabout: Tell us about a problem you are experiencing\n\n---\n\n/kind bug\n\n**What steps did you take and "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 308,
    "preview": "---\nname: Feature enhancement request\nabout: Suggest an idea for this project\n\n---\n\n/kind feature\n\n**Describe the soluti"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 1496,
    "preview": "<!--  Thanks for sending a pull request!  Here are some tips for you:\n1. If this is your first time, read our contributo"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 209,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: gomod\n    directories:\n      - \"**/*\"\n    schedule:\n      interval: daily\n\n  "
  },
  {
    "path": ".github/workflows/lint.yml",
    "chars": 528,
    "preview": "name: Run lint\n\non: [ push, pull_request ]\n\npermissions:\n  contents: read\n\njobs:\n  lint:\n    strategy:\n      matrix:\n   "
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 1299,
    "preview": "name: Test\non: [push, pull_request]\njobs:\n  test:\n    strategy:\n      matrix:\n        go-version: [\"1.21\", \"1.22\", \"1.23"
  },
  {
    "path": ".gitignore",
    "chars": 215,
    "preview": "# OSX leaves these everywhere on SMB shares\n._*\n\n# OSX trash\n.DS_Store\n\n# Eclipse files\n.classpath\n.project\n.settings/**"
  },
  {
    "path": ".golangci.yaml",
    "chars": 101,
    "preview": "linters:\n  disable-all: true\n  enable: # sorted alphabetical\n    - gofmt\n    - misspell\n    - revive\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1576,
    "preview": "# Contributing Guidelines\n\nWelcome to Kubernetes. We are excited about the prospect of you joining our [community](https"
  },
  {
    "path": "LICENSE",
    "chars": 10273,
    "preview": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AN"
  },
  {
    "path": "OWNERS",
    "chars": 244,
    "preview": "# See the OWNERS docs at https://go.k8s.io/owners\nreviewers:\n  - harshanarayana\n  - mengjiao-liu\n  - pohly\napprovers:\n  "
  },
  {
    "path": "README.md",
    "chars": 5142,
    "preview": "klog\n====\n\nklog is a permanent fork of https://github.com/golang/glog.\n\n## Why was klog created?\n\nThe decision to create"
  },
  {
    "path": "RELEASE.md",
    "chars": 508,
    "preview": "# Release Process\n\nThe `klog` is released on an as-needed basis. The process is as follows:\n\n1. An issue is proposing a "
  },
  {
    "path": "SECURITY.md",
    "chars": 1069,
    "preview": "# Security Policy\n\n## Security Announcements\n\nJoin the [kubernetes-security-announce] group for security and vulnerabili"
  },
  {
    "path": "SECURITY_CONTACTS",
    "chars": 585,
    "preview": "# Defined below are the security contacts for this repo.\n#\n# They are the contact point for the Product Security Committ"
  },
  {
    "path": "code-of-conduct.md",
    "chars": 148,
    "preview": "# Kubernetes Community Code of Conduct\n\nPlease refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/co"
  },
  {
    "path": "contextual.go",
    "chars": 7252,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "contextual_slog.go",
    "chars": 898,
    "preview": "//go:build go1.21\n// +build go1.21\n\n/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Versio"
  },
  {
    "path": "contextual_slog_example_test.go",
    "chars": 1143,
    "preview": "//go:build go1.21\n// +build go1.21\n\n/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Versio"
  },
  {
    "path": "contextual_test.go",
    "chars": 2912,
    "preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "examples/benchmarks/benchmarks_test.go",
    "chars": 5130,
    "preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "examples/coexist_glog/coexist_glog.go",
    "chars": 598,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\n\t\"github.com/golang/glog\"\n\t\"k8s.io/klog/examples/util/require\"\n\t\"k8s.io/klog/v2\"\n)\n\nfunc"
  },
  {
    "path": "examples/coexist_klog_v1_and_v2/coexist_klog_v1_and_v2.go",
    "chars": 2767,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\n\tklogv1 \"k8s.io/klog\"\n\tklogv2 \"k8s.io/klog/v2\"\n)\n\n// OutputCallDepth is the stack depth "
  },
  {
    "path": "examples/coexist_klog_v1_and_v2/go.mod",
    "chars": 116,
    "preview": "module k8s.io/klog/examples/coexist_klog_v1_and_v2\n\ngo 1.13\n\nrequire (\n\tk8s.io/klog v1.0.0\n\tk8s.io/klog/v2 v2.0.0\n)\n"
  },
  {
    "path": "examples/flushing/.gitignore",
    "chars": 11,
    "preview": "myfile.log\n"
  },
  {
    "path": "examples/flushing/flushing_test.go",
    "chars": 994,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"testing\"\n\n\t\"go.uber.org/goleak\"\n\n\t\"k8s.io/klog/examples/util/require\"\n\t\"k8s.io/klog/v2\""
  },
  {
    "path": "examples/go.mod",
    "chars": 500,
    "preview": "module k8s.io/klog/examples\n\ngo 1.22.0\n\ntoolchain go1.23.0\n\nrequire (\n\tgithub.com/go-logr/logr v1.4.1\n\tgithub.com/go-log"
  },
  {
    "path": "examples/go.sum",
    "chars": 7162,
    "preview": "github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=\ngithub.com/benbjohnson/clock v1.1.0/"
  },
  {
    "path": "examples/go_vet/go_vet_test.go",
    "chars": 1455,
    "preview": "/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "examples/go_vet/testdata/calls.go",
    "chars": 5192,
    "preview": "/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "examples/klogr/main.go",
    "chars": 611,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\n\t\"k8s.io/klog/examples/util/require\"\n\t\"k8s.io/klog/v2\"\n\t\"k8s.io/klog/v2/klogr\"\n)\n\ntype m"
  },
  {
    "path": "examples/log_file/usage_log_file.go",
    "chars": 393,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\n\t\"k8s.io/klog/examples/util/require\"\n\t\"k8s.io/klog/v2\"\n)\n\nfunc main() {\n\tklog.InitFlags("
  },
  {
    "path": "examples/output_test/output_test.go",
    "chars": 7980,
    "preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "examples/set_output/usage_set_output.go",
    "chars": 397,
    "preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"flag\"\n\t\"fmt\"\n\n\t\"k8s.io/klog/examples/util/require\"\n\t\"k8s.io/klog/v2\"\n)\n\nfunc main() {\n"
  },
  {
    "path": "examples/stderr_threshold_fix/main.go",
    "chars": 1090,
    "preview": "// Example demonstrating the new stderr threshold behavior\npackage main\n\nimport (\n\t\"flag\"\n\n\t\"k8s.io/klog/v2\"\n)\n\nfunc mai"
  },
  {
    "path": "examples/structured_logging/structured_logging.go",
    "chars": 1856,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\n\t\"k8s.io/klog/v2\"\n)\n\n// MyStruct will be logged via %+v\ntype MyStruct struct {\n\tName    "
  },
  {
    "path": "examples/util/require/require.go",
    "chars": 78,
    "preview": "package require\n\nfunc NoError(err error) {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "exit.go",
    "chars": 2385,
    "preview": "// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/\n//\n// Copyright 2013 Google Inc. All"
  },
  {
    "path": "exit_test.go",
    "chars": 1421,
    "preview": "// Copyright 2022 The Kubernetes Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you m"
  },
  {
    "path": "format.go",
    "chars": 2101,
    "preview": "/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "format_test.go",
    "chars": 1933,
    "preview": "/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "go.mod",
    "chars": 71,
    "preview": "module k8s.io/klog/v2\n\ngo 1.21\n\nrequire github.com/go-logr/logr v1.4.1\n"
  },
  {
    "path": "go.sum",
    "chars": 165,
    "preview": "github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=\ngithub.com/go-logr/logr v1.4.1/go.mod h1:"
  },
  {
    "path": "hack/verify-apidiff.sh",
    "chars": 3207,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 The Kubernetes Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "imports.go",
    "chars": 1085,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "integration_tests/internal/main.go",
    "chars": 1030,
    "preview": "/*\n\nThis file is intended to be used as a standin for a klog'ed executable.\n\nIt is called by the integration test via `g"
  },
  {
    "path": "integration_tests/klog_test.go",
    "chars": 11697,
    "preview": "package integration_tests_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"regexp\"\n"
  },
  {
    "path": "internal/buffer/buffer.go",
    "chars": 5118,
    "preview": "// Copyright 2013 Google Inc. All Rights Reserved.\n// Copyright 2022 The Kubernetes Authors.\n//\n// Licensed under the Ap"
  },
  {
    "path": "internal/clock/README.md",
    "chars": 243,
    "preview": "# Clock\n\nThis package provides an interface for time-based operations.  It allows\nmocking time for testing.\n\nThis is a c"
  },
  {
    "path": "internal/clock/clock.go",
    "chars": 4405,
    "preview": "/*\nCopyright 2014 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "internal/clock/testing/fake_clock.go",
    "chars": 8694,
    "preview": "/*\nCopyright 2014 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "internal/clock/testing/simple_interval_clock.go",
    "chars": 1166,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "internal/dbg/dbg.go",
    "chars": 1271,
    "preview": "// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/\n//\n// Copyright 2013 Google Inc. All"
  },
  {
    "path": "internal/serialize/keyvalues.go",
    "chars": 9004,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "internal/serialize/keyvalues_no_slog.go",
    "chars": 3302,
    "preview": "//go:build !go1.21\n// +build !go1.21\n\n/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Vers"
  },
  {
    "path": "internal/serialize/keyvalues_slog.go",
    "chars": 5068,
    "preview": "//go:build go1.21\n// +build go1.21\n\n/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Versio"
  },
  {
    "path": "internal/serialize/keyvalues_test.go",
    "chars": 5564,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "internal/severity/severity.go",
    "chars": 1634,
    "preview": "// Copyright 2013 Google Inc. All Rights Reserved.\n// Copyright 2022 The Kubernetes Authors.\n//\n// Licensed under the Ap"
  },
  {
    "path": "internal/sloghandler/sloghandler_slog.go",
    "chars": 2647,
    "preview": "//go:build go1.21\n// +build go1.21\n\n/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Versio"
  },
  {
    "path": "internal/test/mock.go",
    "chars": 988,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "internal/test/require/require.go",
    "chars": 724,
    "preview": "/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "internal/verbosity/helper_test.go",
    "chars": 666,
    "preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "internal/verbosity/verbosity.go",
    "chars": 8685,
    "preview": "/*\nCopyright 2013 Google Inc. All Rights Reserved.\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache Lic"
  },
  {
    "path": "internal/verbosity/verbosity_test.go",
    "chars": 2609,
    "preview": "/*\nCopyright 2013 Google Inc. All Rights Reserved.\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache Lic"
  },
  {
    "path": "k8s_references.go",
    "chars": 5441,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "k8s_references_slog.go",
    "chars": 1031,
    "preview": "//go:build go1.21\n// +build go1.21\n\n/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Versio"
  },
  {
    "path": "klog.go",
    "chars": 62914,
    "preview": "// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/\n//\n// Copyright 2013 Google Inc. All"
  },
  {
    "path": "klog_file.go",
    "chars": 3701,
    "preview": "// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/\n//\n// Copyright 2013 Google Inc. All"
  },
  {
    "path": "klog_file_others.go",
    "chars": 241,
    "preview": "//go:build !windows\n// +build !windows\n\npackage klog\n\nimport (\n\t\"os/user\"\n)\n\nfunc getUserName() string {\n\tuserNameOnce.D"
  },
  {
    "path": "klog_file_windows.go",
    "chars": 717,
    "preview": "//go:build windows\n// +build windows\n\npackage klog\n\nimport (\n\t\"os\"\n\t\"strings\"\n)\n\nfunc getUserName() string {\n\tuserNameOn"
  },
  {
    "path": "klog_test.go",
    "chars": 60031,
    "preview": "// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/\n//\n// Copyright 2013 Google Inc. All"
  },
  {
    "path": "klog_wrappers_test.go",
    "chars": 1036,
    "preview": "// Copyright 2020 The Kubernetes Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you m"
  },
  {
    "path": "klogr/README.md",
    "chars": 873,
    "preview": "# Minimal Go logging using klog\n\nThis package implements the [logr interface](https://github.com/go-logr/logr)\nin terms "
  },
  {
    "path": "klogr/calldepth-test/call_depth_helper_test.go",
    "chars": 364,
    "preview": "package calldepth\n\nimport (\n\t\"github.com/go-logr/logr\"\n)\n\n// Putting these functions into a separate file makes it possi"
  },
  {
    "path": "klogr/calldepth-test/call_depth_main_test.go",
    "chars": 1448,
    "preview": "// Package calldepth does black-box testing.\n//\n// Another intentional effect is that \"go test\" compiles\n// this into a "
  },
  {
    "path": "klogr/klogr.go",
    "chars": 5562,
    "preview": "// Package klogr implements github.com/go-logr/logr.Logger in terms of\n// k8s.io/klog.\npackage klogr\n\nimport (\n\t\"bytes\"\n"
  },
  {
    "path": "klogr/klogr_test.go",
    "chars": 7269,
    "preview": "package klogr\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"k8s.io/klog/v2\"\n\t\"k8s.io/klog/v2/in"
  },
  {
    "path": "klogr/output_test.go",
    "chars": 974,
    "preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "klogr.go",
    "chars": 3135,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "klogr_helper_test.go",
    "chars": 1093,
    "preview": "/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "klogr_slog.go",
    "chars": 2710,
    "preview": "//go:build go1.21\n// +build go1.21\n\n/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Versio"
  },
  {
    "path": "klogr_slog_test.go",
    "chars": 4027,
    "preview": "//go:build go1.21\n// +build go1.21\n\n/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Versio"
  },
  {
    "path": "klogr_test.go",
    "chars": 1882,
    "preview": "/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "ktesting/contextual_test.go",
    "chars": 1393,
    "preview": "/*\nCopyright 2019 The Kubernetes Authors.\nCopyright 2020 Intel Corporation.\n\nSPDX-License-Identifier: Apache-2.0\n*/\n\npac"
  },
  {
    "path": "ktesting/example/example_test.go",
    "chars": 1150,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nSPDX-License-Identifier: Apache-2.0\n*/\n\npackage example\n\nimport (\n\t\"fmt\"\n\t\"te"
  },
  {
    "path": "ktesting/example_test.go",
    "chars": 5190,
    "preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "ktesting/helper_test.go",
    "chars": 269,
    "preview": "/*\nCopyright 2025 The Kubernetes Authors.\n\nSPDX-License-Identifier: Apache-2.0\n*/\n\npackage ktesting_test\n\nimport (\n\t\"k8s"
  },
  {
    "path": "ktesting/init/init.go",
    "chars": 875,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "ktesting/main_test.go",
    "chars": 227,
    "preview": "/*\nCopyright 2025 The Kubernetes Authors.\n\nSPDX-License-Identifier: Apache-2.0\n*/\n\npackage ktesting_test\n\nimport (\n\t\"fla"
  },
  {
    "path": "ktesting/options.go",
    "chars": 4472,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "ktesting/setup.go",
    "chars": 1294,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "ktesting/testinglogger.go",
    "chars": 11180,
    "preview": "/*\nCopyright 2019 The Kubernetes Authors.\nCopyright 2020 Intel Corporation.\n\nLicensed under the Apache License, Version "
  },
  {
    "path": "ktesting/testinglogger_test.go",
    "chars": 9959,
    "preview": "/*\nCopyright 2019 The Kubernetes Authors.\nCopyright 2020 Intel Corporation.\n\nSPDX-License-Identifier: Apache-2.0\n*/\n\npac"
  },
  {
    "path": "output_test.go",
    "chars": 1252,
    "preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "safeptr.go",
    "chars": 1143,
    "preview": "//go:build go1.18\n// +build go1.18\n\n/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Versio"
  },
  {
    "path": "safeptr_test.go",
    "chars": 1043,
    "preview": "//go:build go1.18\n// +build go1.18\n\n/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Versio"
  },
  {
    "path": "stderr_threshold_test.go",
    "chars": 11354,
    "preview": "// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/\n//\n// Copyright 2026 The Kubernetes "
  },
  {
    "path": "test/output.go",
    "chars": 34218,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "test/output_helper.go",
    "chars": 884,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "test/zapr.go",
    "chars": 20425,
    "preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "textlogger/example_test.go",
    "chars": 1561,
    "preview": "/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "textlogger/options.go",
    "chars": 5299,
    "preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "textlogger/output_test.go",
    "chars": 1516,
    "preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "textlogger/textlogger.go",
    "chars": 5615,
    "preview": "/*\nCopyright 2019 The Kubernetes Authors.\nCopyright 2020 Intel Corporation.\n\nLicensed under the Apache License, Version "
  },
  {
    "path": "textlogger/textlogger_slog.go",
    "chars": 1306,
    "preview": "//go:build go1.21\n// +build go1.21\n\n/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Versio"
  },
  {
    "path": "textlogger/textlogger_slog_test.go",
    "chars": 3572,
    "preview": "//go:build go1.21\n// +build go1.21\n\n/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Versio"
  },
  {
    "path": "textlogger/textlogger_test.go",
    "chars": 3950,
    "preview": "/*\nCopyright 2023 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  }
]

About this extraction

This page contains the full source code of the kubernetes/klog GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 107 files (442.4 KB), approximately 128.7k tokens, and a symbol index with 705 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!