npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

generator-jhipster-loggingmodule

v2.0.0

Published

JHipster module that logs every API request lifecycle (start, finish, error) to a dedicated rolling log file

Downloads

294

Readme

generator-jhipster-loggingmodule

A JHipster module that logs every API request lifecycle — start, finish, and error — to a dedicated rolling log file, completely separate from the main application log.


Table of Contents


Overview

generator-jhipster-loggingmodule is a Yeoman/JHipster generator module that installs structured API request lifecycle logging into any existing JHipster Spring Boot application.

Once installed, it automatically:

  • Intercepts every incoming HTTP request via a Spring OncePerRequestFilter
  • Logs three distinct lifecycle events per request: START, FINISH, and ERROR
  • Writes all logs to a dedicated rolling log file (separate from the main application log)
  • Includes a unique request ID, authenticated user, timestamp, HTTP method, URI, and request/response body details in every log entry

Key goals of the project:

  • Provide full observability of API request lifecycles without touching application code
  • Produce structured, traceable logs that can be correlated across START/FINISH/ERROR events via a shared Request ID
  • Keep the log file manageable with automatic weekly rotation and 30-day retention

Features

  • Three-phase lifecycle logging — START (before handler), FINISH (200/201/204 responses), ERROR (non-2xx or unhandled exception)
  • Unique Request ID — a UUID generated per request, shared across all three phases for easy tracing
  • Authenticated user logging — captures the jhi_user.login from Spring Security context
  • Mandatory request body logging — always logged at START and on error
  • Error response body logging — response body is always captured and logged for non-2xx responses
  • Configurable HTTP method filtering — choose which methods (GET, POST, PUT, DELETE) to log
  • Dedicated rolling log file — completely separate from the main application log
  • Configurable log rotation — choose daily, weekly, or monthly rolling at install time; configurable via application.yml afterwards
  • Optional database logging — optionally persist every log entry to a MySQL api_request_log table; table is created automatically via Liquibase on first app start
  • Zero-code installation — a single yo jhipster-loggingmodule command wires everything into your project
  • Idempotent generator — safe to re-run; will not duplicate configuration
  • Configurable via application.yml — no code changes needed to adjust settings

Tech Stack

Module (Generator):

  • Node.js
  • Yeoman (yo)
  • generator-jhipster (BaseGenerator)
  • EJS templating

Generated Components (Target App):

  • Java / Spring Boot
  • Spring Web (OncePerRequestFilter, ContentCachingResponseWrapper)
  • Spring Security (SecurityContextHolder)
  • Logback (RollingFileAppender, TimeBasedRollingPolicy)
  • Jakarta Servlet API

Testing:

  • Mocha
  • yeoman-assert
  • yeoman-test

Architecture

The module follows a generator → target app injection pattern:

generator-jhipster-loggingmodule (this repo)
        │
        │  yo jhipster-loggingmodule
        ▼
Your JHipster Spring Boot App
        │
        ├── ApiLoggingFilter.java        ← Spring filter (intercepts requests)
        ├── ApiLoggingProperties.java    ← @ConfigurationProperties bean
        ├── logback-spring.xml           ← API_FILE appender injected
        └── application.yml             ← api-logging: block appended

Runtime request flow:

Incoming HTTP Request
        │
        ▼
CachedBodyRequestWrapper        ← buffers request body for multi-read
ContentCachingResponseWrapper   ← buffers response body for logging
        │
        ▼
logStarted(...)                 ← >>> REQUEST STARTED  (before handler)
        │
        ▼
chain.doFilter(...)             ← application handler runs here
        │
        ├── status 200/201/204 → logFinished(...)   ← <<< REQUEST FINISHED
        ├── status 4xx/5xx     → logHttpError(...)  ← !!! REQUEST ERROR
        └── exception thrown   → logError(...)      ← !!! REQUEST ERROR
        │
        ▼
wrappedResponse.copyBodyToResponse()   ← sends response to client

Configuration connection:

application.yml (api-logging.log-file)
        │
        ├──► ApiLoggingProperties.java   (Spring binds value into bean)
        │           └── ApiLoggingFilter reads properties at runtime
        │
        └──► logback-spring.xml          (<springProperty> reads same key)
                    └── API_FILE appender → logs/api-requests.log

Project Structure

logging-module/
│
├── generators/
│   └── app/
│       ├── index.js                      # Main generator — all logic lives here
│       └── templates/
│           ├── ApiLoggingFilter.java     # Spring filter template (EJS)
│           └── ApiLoggingProperties.java # Configuration properties template (EJS)
│
├── test/
│   └── app.spec.js                       # Mocha unit tests for the generator
│
├── package.json                          # Yeoman module definition & npm metadata
└── README.md

Getting Started

Requirements:

  • Node.js 12+
  • npm 6+
  • Yeoman (npm install -g yo)
  • An existing JHipster Spring Boot project (must have .yo-rc.json)
  • Java 11+ / Spring Boot 3.x (Jakarta EE)

Installation

Install from npm (recommended):

npm install -g generator-jhipster-loggingmodule

Or install locally for development:

git clone https://your-repo/logging-module.git
cd logging-module
npm install
npm link

Run the generator inside your JHipster project:

cd /path/to/your-jhipster-app
yo jhipster-loggingmodule

The generator will ask three questions:

  1. Enable API request logging? — default: Yes
  2. Log file path — default: logs/api-requests.log
  3. Which HTTP methods to log? — checkbox: GET, POST, PUT, DELETE (all selected by default)

To skip all prompts and use defaults:

yo jhipster-loggingmodule default

Files generated / modified in the target app:

src/
├── main/
│   ├── java/<your-package>/
│   │   ├── config/
│   │   │   └── ApiLoggingProperties.java   ← NEW
│   │   └── logging/
│   │       └── ApiLoggingFilter.java        ← NEW
│   └── resources/
│       ├── logback-spring.xml               ← MODIFIED (API_FILE appender injected)
│       └── config/
│           └── application.yml              ← MODIFIED (api-logging block appended)

Configuration

All settings live under the api-logging prefix in application.yml:

api-logging:
  enabled: true                                            # Set to false to disable all logging entirely
  log-file: logs/api-requests.log                         # Path relative to JVM working directory (project root)
  log-methods:                                            # Only requests with these methods will be logged
    - GET
    - POST
    - PUT
    - DELETE
  rolling-pattern: logs/api-requests.log.%d{yyyy-'W'ww}  # Archive filename pattern — controls rolling frequency
  max-history: 4                                          # Number of archives to keep before older ones are deleted

Configuration reference:

| YAML Key | Default | Description | |-------------------------------|------------------------------------------------|-----------------------------------------------------------------| | api-logging.enabled | true | Activates or deactivates the filter entirely | | api-logging.log-file | logs/api-requests.log | Path of the active log file (relative to project root) | | api-logging.log-methods | [GET, POST, PUT, DELETE] | HTTP methods to log; others are silently skipped | | api-logging.rolling-pattern | logs/api-requests.log.%d{yyyy-'W'ww} | Archive filename pattern — controls rolling frequency | | api-logging.max-history | 4 | Number of rolling archives to keep; older ones are auto-deleted | | api-logging.log-to-database | false | Also persist log entries to the api_request_log database table|

Changes take effect on next application restart. No code changes or regeneration needed.

Adjusting the rolling frequency:

Change rolling-pattern to control how often a new archive file is created:

| rolling-pattern value | Rolling frequency | Recommended max-history | |-------------------------------------------------|-------------------|---------------------------| | logs/api-requests.log.%d{yyyy-MM-dd} | Daily | 30 (keeps 30 days) | | logs/api-requests.log.%d{yyyy-'W'ww} | Weekly (default) | 4 (keeps ~30 days) | | logs/api-requests.log.%d{yyyy-MM} | Monthly | 12 (keeps 1 year) |

The generator will prompt you to choose daily/weekly/monthly during installation and will automatically set the correct default for max-history. Both values can be freely changed in application.yml at any time after installation.


Database Logging (Optional)

When prompted during installation, you can choose to also save every log entry to the database. This is completely optional — file logging is always active regardless.

What gets generated when you say Yes:

src/
├── main/
│   ├── java/<your-package>/
│   │   ├── config/
│   │   │   └── LogApi.java                 ← NEW: @LogApi annotation
│   │   ├── domain/
│   │   │   └── ApiRequestLog.java          ← NEW: JPA entity
│   │   └── repository/
│   │       └── ApiRequestLogRepository.java ← NEW: Spring Data repository
│   └── resources/config/liquibase/
│       ├── master.xml                      ← MODIFIED: include injected
│       └── changelog/
│           └── api_request_log.xml         ← NEW: Liquibase changelog

Controlling which endpoints are logged to the database — @LogApi:

Database logging is opt-in per endpoint via the @LogApi annotation. File logging is always active for all matched methods regardless of this annotation.

Place @LogApi on a specific method to log only that endpoint:

import com.example.myapp.config.LogApi;

@RestController
@RequestMapping("/api")
public class UserResource {

    @LogApi                          // ← only this method is saved to DB
    @GetMapping("/users")
    public List<User> getAllUsers() { ... }

    @PostMapping("/users")           // ← file-logged only, NOT saved to DB
    public User createUser(@RequestBody User user) { ... }
}

Place @LogApi on an entire controller to log all its methods:

@LogApi                              // ← every method in this class is saved to DB
@RestController
@RequestMapping("/api/payments")
public class PaymentResource {

    @PostMapping("/charge")
    public PaymentResult charge(@RequestBody ChargeRequest req) { ... }

    @GetMapping("/history")
    public List<Payment> getHistory() { ... }
}

Note: Method-level @LogApi takes precedence over class-level. You can annotate a whole controller with @LogApi and then the filter will match any method inside it.

Table structure (api_request_log):

| Column | Type | Description | |-----------------|---------------|----------------------------------------------------------------------| | id | BIGINT (PK) | Auto-increment primary key | | request_id | VARCHAR(36) | UUID shared across all phases of the same request | | phase | VARCHAR(10) | START, FINISH, or ERROR | | log_date_time | DATETIME | Timestamp of the log entry | | user_login | VARCHAR(50) | Authenticated user login, or anonymous | | http_method | VARCHAR(10) | HTTP method (GET, POST, etc.) | | uri | VARCHAR(500) | Request URI including query string | | status | INTEGER | HTTP response status — null for START phase | | duration_ms | BIGINT | Handler duration in ms — null for START phase | | req_body | TEXT (CLOB) | Request body — present on START and exception ERROR phases | | res_body | TEXT (CLOB) | Response body — present on HTTP error (non-2xx) ERROR phase only | | error_type | VARCHAR(255) | Exception class name — present on exception ERROR phase only | | error_message | TEXT (CLOB) | Exception message — present on exception ERROR phase only |

How to query your logs:

-- All events for a specific request (trace full lifecycle)
SELECT * FROM api_request_log WHERE request_id = 'f47ac10b-...' ORDER BY log_date_time;

-- All errors in the last 24 hours
SELECT * FROM api_request_log WHERE phase = 'ERROR' AND log_date_time >= NOW() - INTERVAL 1 DAY;

-- Slowest requests today
SELECT uri, http_method, duration_ms, user_login
FROM api_request_log
WHERE phase = 'FINISH' AND log_date_time >= CURDATE()
ORDER BY duration_ms DESC LIMIT 20;

-- Requests by a specific user
SELECT * FROM api_request_log WHERE user_login = 'john.doe' ORDER BY log_date_time DESC;

Enabling/disabling at runtime:

Change api-logging.log-to-database in application.yml and restart — no code changes needed:

api-logging:
  log-to-database: true   # set to false to stop DB writes without removing the table

Note: If a database error occurs while saving a log entry, it is caught silently and logged as a warning in the file — the original HTTP request is never affected.


Usage

After installation, simply start your JHipster application normally:

./mvnw spring-boot:run

The filter activates automatically. Log entries will appear in logs/api-requests.log as soon as the first matching HTTP request is received.


Log Format

Each request produces up to two log entries — one at START and one at FINISH or ERROR.

START — fired before the handler runs:

>>> REQUEST STARTED
  Date       : 2025-03-10 14:32:01
  Request-ID : f47ac10b-58cc-4372-a567-0e02b2c3d479
  User       : john.doe
  Method     : POST
  URI        : /api/users
  ReqBody    : {"login":"alice","email":"[email protected]"}

FINISH — fired for 200/201/204 responses:

<<< REQUEST FINISHED
  Date       : 2025-03-10 14:32:01
  Request-ID : f47ac10b-58cc-4372-a567-0e02b2c3d479
  User       : john.doe
  Method     : POST
  URI        : /api/users
  Status     : 201
  Duration   : 47 ms

ERROR — fired for non-2xx HTTP responses or unhandled exceptions:

!!! REQUEST ERROR
  Date       : 2025-03-10 14:32:05
  Request-ID : 9b2e1c3a-1234-4abc-8def-000011112222
  User       : jane.doe
  Method     : DELETE
  URI        : /api/users/999
  Status     : 404
  Duration   : 12 ms
  ResBody    : {"title":"Not Found","status":404,"detail":"User 999 not found"}

The Request-ID is identical across START and FINISH/ERROR entries for the same request, allowing you to correlate them in the log file.


Testing

Run the generator unit tests:

npm test

Test coverage:

| Test | What it verifies | |------|-----------------| | generates ApiLoggingFilter | File exists at the correct path | | generates ApiLoggingProperties | File exists at the correct path | | ApiLoggingFilter has correct package | EJS substitution worked correctly | | ApiLoggingProperties uses @ConfigurationProperties | Annotation is present | | logback-spring.xml has API_FILE appender | Appender was injected | | logback-spring.xml has API_REQUEST_LOG logger | Logger was injected | | logback-spring.xml reads log path from Spring property | <springProperty> with correct source attribute |


Deployment

Publishing to npm:

Ensure you are logged in:

npm whoami
npm login   # if not logged in

Publish the package:

npm publish

Note: npm requires 2FA or a Granular Access Token to publish packages.
To generate a token: npm website → Account Settings → Access Tokens → Generate New Token → Granular Access Token → Read and Write on this package.

Then publish using the token:

npm publish --_authToken=<your-token>

Verify the published package:

npm view generator-jhipster-loggingmodule

CI/CD

CI/CD is configured using GitHub Actions (.github/workflows/github-ci.yml).

Pipeline steps:

  1. Install Node.js dependencies (npm install)
  2. Run unit tests (npm test)
  3. Build / lint validation
  4. Publish to npm on release tag (with access token from GitHub Secrets)

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/your-feature)
  3. Make your changes and add/update tests in test/app.spec.js
  4. Ensure all tests pass (npm test)
  5. Commit your changes (git commit -m "feat: add your feature")
  6. Open a Pull Request against main

Security

  • The filter reads the authenticated user from Spring Security context (SecurityContextHolder) — it does not store or transmit credentials
  • Request bodies are logged as-is; avoid logging endpoints that handle raw passwords or sensitive tokens
  • The log file is written to the local filesystem; ensure appropriate file permissions are set on the logs/ directory in production
  • To disable logging entirely, set api-logging.enabled: false in application.yml — no redeployment required, only a restart

License

MIT License


Contact

Maintainer: mariam.ibrahim