{"id":15044705,"url":"https://github.com/johndeere/work-tracker","last_synced_at":"2025-10-04T05:31:39.507Z","repository":{"id":46193125,"uuid":"144751850","full_name":"JohnDeere/work-tracker","owner":"JohnDeere","description":"Observe and protect your Java web application.","archived":true,"fork":false,"pushed_at":"2023-05-19T02:22:20.000Z","size":775,"stargazers_count":5,"open_issues_count":12,"forks_count":12,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-07-18T20:54:19.400Z","etag":null,"topics":["elasticsearch","java","java11","java8","mdc","metadata","observability","spring","spring-boot","sre"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JohnDeere.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-14T17:28:47.000Z","updated_at":"2025-03-22T05:53:09.000Z","dependencies_parsed_at":"2024-09-28T23:20:49.183Z","dependency_job_id":"ed88bfec-6a25-4dc8-bdff-43012c1461e3","html_url":"https://github.com/JohnDeere/work-tracker","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/JohnDeere/work-tracker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JohnDeere%2Fwork-tracker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JohnDeere%2Fwork-tracker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JohnDeere%2Fwork-tracker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JohnDeere%2Fwork-tracker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JohnDeere","download_url":"https://codeload.github.com/JohnDeere/work-tracker/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JohnDeere%2Fwork-tracker/sbom","scorecard":{"id":73650,"data":{"date":"2025-08-11","repo":{"name":"github.com/JohnDeere/work-tracker","commit":"4b98e9cd19253e8d5cbaa273b6ee2d5004b42c26"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.8,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/2 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"project is archived","details":["Warn: Repository is archived."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql.yml:28","Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql.yml:29","Warn: no topLevel permission defined: .github/workflows/codeql.yml:1","Warn: no topLevel permission defined: .github/workflows/maven.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/JohnDeere/work-tracker/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:47: update your workflow using https://app.stepsecurity.io/secureworkflow/JohnDeere/work-tracker/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:61: update your workflow using https://app.stepsecurity.io/secureworkflow/JohnDeere/work-tracker/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:74: update your workflow using https://app.stepsecurity.io/secureworkflow/JohnDeere/work-tracker/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/JohnDeere/work-tracker/maven.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/JohnDeere/work-tracker/maven.yml/master?enable=pin","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":7,"reason":"SAST tool detected but not run on all commits","details":["Info: SAST configuration detected: CodeQL","Warn: 0 commits out of 29 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":5,"reason":"5 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-vmq6-5m68-f53m","Warn: Project is vulnerable to: GHSA-668q-qrv7-99fm","Warn: Project is vulnerable to: GHSA-6v67-2wr5-gvf4","Warn: Project is vulnerable to: GHSA-pr98-23f8-jwxv","Warn: Project is vulnerable to: GHSA-h46c-h94j-95f3"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-15T04:22:26.976Z","repository_id":46193125,"created_at":"2025-08-15T04:22:26.976Z","updated_at":"2025-08-15T04:22:26.976Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278267490,"owners_count":25958875,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elasticsearch","java","java11","java8","mdc","metadata","observability","spring","spring-boot","sre"],"created_at":"2024-09-24T20:50:55.953Z","updated_at":"2025-10-04T05:31:39.099Z","avatar_url":"https://github.com/JohnDeere.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/JohnDeere/work-tracker.svg?branch=master)](https://travis-ci.org/JohnDeere/work-tracker)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.deere.isg.work-tracker/work-tracker/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.deere.isg.work-tracker/work-tracker)\n[![DepShield Badge](https://depshield.sonatype.org/badges/JohnDeere/work-tracker/depshield.svg)](https://depshield.github.io)\n\n# Work Tracker\nA library to monitor threads and requests. It provides advanced logging capabilities, and protects the application's JVMs from too many requests and from long running requests that would eventually turn into zombies.\n\n**Features:**\n1. Has the ability to log contextual thread metadata to `Elasticsearch` for web requests\n2. Checks if the number of threads do not exceed the maximum number of\nresources than the JVM permits (i.e. database connections, memory resources, etc.). `RequestBouncer` handles those checks\nand allows new threads to proceed only if they are within the `Connection Limits`.  \n3. Kills threads that take too long to respond, aka [`Zombies`](doc/ZOMBIES.md)\n4. Adds exception names to the logs of faulty requests for tracking bugs better, see `RootCauseTurboFilter`\n5. Provides contextual thread metadata for background tasks, see `MdcExecutor`\n\n## Setup\n- **Java Web Projects:** See [Readme](./work-tracker-servlet)\n- **Spring Projects:** See [Readme](./work-tracker-spring)\n- **Spring Boot Projects:** See [Readme](./work-tracker-spring-boot)\n- **Other Projects:** See [Readme](./work-tracker-core)\n\n## Common Configuration and Usage\nThe following instructions apply to all of work-tracker's support modules.\n\n### Whitelisting Jobs\nIf you expect a job to take longer than 5 minutes (i.e. uploading/downloading a file), you may want to `whitelist` that job. Use `Work#setMaxTime(long)` to update the time for Zombie detection.\n\n### Logback features specific to this library\n- [RootCauseTurboFilter](./work-tracker-core/src/main/java/com/deere/isg/worktracker/RootCauseTurboFilter.java)\n\nThis turbo filter adds the class name of the `root cause` and the `cause` to the MDC when an exception occurs. Those class names will exist until the request ends to provide an easy way to trace down a faulty request from the beginning of the exception to the end of that request.\n```groovy\nturboFilter(RootCauseTurboFilter)\n```\n\nOptional configuration for field names:\n```groovy\n//...\nturboFilter(RootCauseTurboFilter) {\n  causeFieldName = \"cause_field_name\" // Optional, if you want some other value for causeFieldName\n  rootCauseFieldName = \"root_cause_field_name\" // Optional, if you want some other value for rootCauseFieldName\n}\n\n//...\n```\n\n- [MdcThreadNameJsonProvider](./work-tracker-core/src/main/java/com/deere/isg/worktracker/MdcThreadNameJsonProvider.java)\n\nThis JSON Provider is **necessary** if `ZombieDetector` is used. This provider gets the `thread name` of the actual zombie work instead of the `ZombieLogger` class. Thus, making it easier to find out what work was zombie\n\n**Configuration:**\n```groovy\nencoder(LoggingEventCompositeJsonEncoder) {\n   providers(LoggingEventJsonProviders) {\n      //...\n      mdc(MdcJsonProvider) {\n         excludeMdcKeyName = 'thread_name' // Avoid the need to overwrite by threadName()\n      }\n      threadName(MdcThreadNameJsonProvider)\n      //...\n  }\n}\n```\n\nSee [example](./work-tracker-examples/java-example/src/main/resources/logback.groovy)\n\n---\n\n### Logging Utilities\n#### Using Logger to log information\n```java\nprivate Logger logger = LoggerFactory.getLogger(CurrentClass.class);\n//...\nlogger.info(\"This is an info log\"); // log some information\nlogger.warn(\"This is a warn log\"); // log a warning\n\ntry {\n  //...\n} catch(Exception e){\n  logger.error(\"This is an error log\", e); // log an error\n}\n```\n\n#### Using `putInContext` to add context to logs\n`putInContext` is a wrapper for the `MDC (Mapped Diagnostic Context)`. It puts the key-value pair in the MDC and in the current work payload, thus, making sure that the `ZombieDetector` will have all the work metadata to log to Elasticsearch in the case where you need to track and debug your application for those Zombies.\n\nIf you want some context variables to persist for a given request across multiple logs, use the `putInContext` to add those context variables. For example:\n```java\n// Use the OutstandingWork to put the values to the MDC for the current work\noutstandingWork.putInContext(\"some_id\", \"some value\");\n```\n\n**Retrieving the OutstandingWork in the `Java Module` (i.e. using `HttpServlet`)**\n```java\n// Get the OutstandingWork from the Servlet Context\n@Override\nprotected void doGet(HttpServletRequest request, HttpServletResponse response)\n    throws ServletException, IOException {\n    OutstandingWork\u003c?\u003e outstandingWork = (OutstandingWork\u003c?\u003e) request\n        .getServletContext().getAttribute(OUTSTANDING_ATTR);\n    //... add your values to the context using putInContext\n}\n```\n\nTo make life simpler, you can also have a utility class to put the context in the outstandingWork. See [example](./work-tracker-examples/java-example/src/main/java/com/deere/example/MDC.java), and its [initialization](./work-tracker-examples/java-example/src/main/java/com/deere/example/WorkTrackerContextListener.java#)\n\n**Retrieving the OutstandingWork in the `Spring Module`**\n```java\n// Using field injection\n@Autowired\nprivate OutstandingWork\u003c? extends SpringWork\u003e outstandingWork;\n//...\n```\n```java\n// OR using constructor injection (use either one, but not both)\nprivate OutstandingWork\u003c? extends SpringWork\u003e outstandingWork;\n//...\npublic SomeClass(@Autowired OutstandingWork\u003c? extends SpringWork\u003e outstandingWork) {\n  this.outstandingWork = outstandingWork;\n}\n```\n\nNow, each of your subsequent logs will have those values in the MDC, unless you clear the MDC (and this library automatically clears the MDC at the end of each request to avoid having stale context).\n\n#### Using Structured Arguments for individual log context\nIf some context variables are specific to a single log (i.e. the sender id for a certain message, elapsed time, etc.), use `StructuredArguments.keyValue()` to add those context variables. Those variables will not persist across all the logs but they will be available for that log only. For example:\n```java\nlogger.info(\"{} sent a message\", keyValue(\"sender_id\", \"some sender value\"));\n```\n\n`keyValue` will turn the message into `\"sender_id=some sender value sent a message\"`, while also creating an index in Elasticsearch for `sender_id` to make it easier to search for a particular sender_id in Kibana.\n\n**Note:** Make sure that the `key` for `MDC` and `Structured Arguments` is in `snake_case (and lower case)` as suggested by Elasticsearch's [Naming Conventions](https://www.elastic.co/guide/en/beats/devguide/current/event-conventions.html). These naming conventions make it easy to search for those keys in `Kibana` as the keys will be optimized by Elastic Search.\n\n\n---\n\n## Contributing to this library\nPlease see the [Contribution Guidelines](./.github/CONTRIBUTING.md).\n\n### Running tests\n```bash\nmvn clean verify\n```\n\n### Running example projects\nDon't know how to start, have a look at these [examples](./work-tracker-examples)\n\n\n## Bump Version For Release\nRun the following bash command and commit the change:\n```bash\nbash build/bump_version.sh MAJOR|MINOR|PATCH\n```   \n\nExample:\n```bash\nbash build/bump_version.sh MINOR\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohndeere%2Fwork-tracker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohndeere%2Fwork-tracker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohndeere%2Fwork-tracker/lists"}