xref: /spdk/lib/log/log_deprecated.c (revision f7b31b2b9679b48e9e13514a6b668058bb45fd56)
15b50d3e8SMike Gerdts /*   SPDX-License-Identifier: BSD-3-Clause
25b50d3e8SMike Gerdts  *   Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
35b50d3e8SMike Gerdts  */
45b50d3e8SMike Gerdts 
55b50d3e8SMike Gerdts #include "spdk/stdinc.h"
65b50d3e8SMike Gerdts #include "spdk/string.h"
75b50d3e8SMike Gerdts #include "spdk/thread.h"
85b50d3e8SMike Gerdts #include "spdk/util.h"
95b50d3e8SMike Gerdts #include "spdk/log.h"
105b50d3e8SMike Gerdts 
115b50d3e8SMike Gerdts struct spdk_deprecation {
127c1a27afSSlawomir Ptak 	const char tag[64];
135b50d3e8SMike Gerdts 	const char desc[64];
145b50d3e8SMike Gerdts 	const char remove[16];
155b50d3e8SMike Gerdts 	TAILQ_ENTRY(spdk_deprecation) link;
165b50d3e8SMike Gerdts 	uint64_t hits;
175b50d3e8SMike Gerdts 	/* How often (nanoseconds) to log. */
185b50d3e8SMike Gerdts 	uint64_t interval;
195b50d3e8SMike Gerdts 	/* How many messages were not logged due to rate limiting */
205b50d3e8SMike Gerdts 	uint32_t deferred;
215b50d3e8SMike Gerdts 	/* CLOCK_MONOTONIC microseconds since g_deprecation_epoch when last warning was logged */
225b50d3e8SMike Gerdts 	uint64_t last_log;
235b50d3e8SMike Gerdts };
245b50d3e8SMike Gerdts 
255b50d3e8SMike Gerdts static TAILQ_HEAD(, spdk_deprecation) g_deprecations = TAILQ_HEAD_INITIALIZER(g_deprecations);
26*f7b31b2bSPierre Lestringant static struct timespec g_deprecation_epoch;
275b50d3e8SMike Gerdts 
285b50d3e8SMike Gerdts static void
295b50d3e8SMike Gerdts __attribute__((constructor))
305b50d3e8SMike Gerdts deprecation_init(void)
315b50d3e8SMike Gerdts {
325b50d3e8SMike Gerdts 	clock_gettime(CLOCK_MONOTONIC, &g_deprecation_epoch);
335b50d3e8SMike Gerdts }
345b50d3e8SMike Gerdts 
355b50d3e8SMike Gerdts static inline uint64_t
365b50d3e8SMike Gerdts get_ns_since_epoch(void)
375b50d3e8SMike Gerdts {
385b50d3e8SMike Gerdts 	struct timespec now;
395b50d3e8SMike Gerdts 
405b50d3e8SMike Gerdts 	clock_gettime(CLOCK_MONOTONIC, &now);
415b50d3e8SMike Gerdts 	return (now.tv_sec - g_deprecation_epoch.tv_sec) * SPDK_SEC_TO_NSEC +
425b50d3e8SMike Gerdts 	       now.tv_nsec - g_deprecation_epoch.tv_nsec;
435b50d3e8SMike Gerdts }
445b50d3e8SMike Gerdts 
455b50d3e8SMike Gerdts int
465b50d3e8SMike Gerdts spdk_log_deprecation_register(const char *tag, const char *description, const char *remove_release,
475b50d3e8SMike Gerdts 			      uint32_t rate_limit_seconds, struct spdk_deprecation **depp)
485b50d3e8SMike Gerdts {
495b50d3e8SMike Gerdts 	struct spdk_deprecation *dep;
505b50d3e8SMike Gerdts 
515b50d3e8SMike Gerdts 	assert(strnlen(tag, sizeof(dep->tag)) < sizeof(dep->tag));
525b50d3e8SMike Gerdts 	assert(strnlen(description, sizeof(dep->desc)) < sizeof(dep->desc));
535b50d3e8SMike Gerdts 	assert(strnlen(remove_release, sizeof(dep->remove)) < sizeof(dep->remove));
545b50d3e8SMike Gerdts 
555b50d3e8SMike Gerdts 	dep = calloc(1, sizeof(*dep));
565b50d3e8SMike Gerdts 	if (dep == NULL) {
575b50d3e8SMike Gerdts 		return -ENOMEM;
585b50d3e8SMike Gerdts 	}
595b50d3e8SMike Gerdts 
605b50d3e8SMike Gerdts 	snprintf((char *)dep->tag, sizeof(dep->tag), "%s", tag);
615b50d3e8SMike Gerdts 	snprintf((char *)dep->desc, sizeof(dep->desc), "%s", description);
625b50d3e8SMike Gerdts 	snprintf((char *)dep->remove, sizeof(dep->remove), "%s", remove_release);
635b50d3e8SMike Gerdts 	dep->interval = rate_limit_seconds * SPDK_SEC_TO_NSEC;
645b50d3e8SMike Gerdts 
655b50d3e8SMike Gerdts 	TAILQ_INSERT_TAIL(&g_deprecations, dep, link);
665b50d3e8SMike Gerdts 	*depp = dep;
675b50d3e8SMike Gerdts 	return 0;
685b50d3e8SMike Gerdts }
695b50d3e8SMike Gerdts 
705b50d3e8SMike Gerdts /*
715b50d3e8SMike Gerdts  * There is potential for races between pthreads leading to over or under reporting of times that
725b50d3e8SMike Gerdts  * deprecated code was hit. If this function is called in a hot path where that is likely, we care
735b50d3e8SMike Gerdts  * more about performance than accuracy of the error counts. The important thing is that at least
745b50d3e8SMike Gerdts  * one of the racing updates the hits counter to non-zero and the warning is logged at least once.
755b50d3e8SMike Gerdts  */
765b50d3e8SMike Gerdts void
775b50d3e8SMike Gerdts spdk_log_deprecated(struct spdk_deprecation *dep, const char *file, uint32_t line, const char *func)
785b50d3e8SMike Gerdts {
795b50d3e8SMike Gerdts 	uint64_t now = get_ns_since_epoch();
805b50d3e8SMike Gerdts 
815b50d3e8SMike Gerdts 	if (dep == NULL) {
825b50d3e8SMike Gerdts 		SPDK_ERRLOG("NULL deprecation passed from %s:%u:%s\n", file, line, func);
835b50d3e8SMike Gerdts 		assert(false);
845b50d3e8SMike Gerdts 		return;
855b50d3e8SMike Gerdts 	}
865b50d3e8SMike Gerdts 
875b50d3e8SMike Gerdts 	dep->hits++;
885b50d3e8SMike Gerdts 
895b50d3e8SMike Gerdts 	if (dep->interval != 0) {
905b50d3e8SMike Gerdts 		if (dep->last_log != 0 && now < dep->last_log + dep->interval) {
915b50d3e8SMike Gerdts 			dep->deferred++;
925b50d3e8SMike Gerdts 			return;
935b50d3e8SMike Gerdts 		}
945b50d3e8SMike Gerdts 	}
955b50d3e8SMike Gerdts 
965b50d3e8SMike Gerdts 	dep->last_log = now;
975b50d3e8SMike Gerdts 
985b50d3e8SMike Gerdts 	spdk_log(SPDK_LOG_WARN, file, line, func, "%s: deprecated feature %s to be removed in %s\n",
995b50d3e8SMike Gerdts 		 dep->tag, dep->desc, dep->remove);
1005b50d3e8SMike Gerdts 	if (dep->deferred != 0) {
1015b50d3e8SMike Gerdts 		SPDK_WARNLOG("%s: %u messages suppressed\n", dep->tag, dep->deferred);
1025b50d3e8SMike Gerdts 		dep->deferred = 0;
1035b50d3e8SMike Gerdts 	}
1045b50d3e8SMike Gerdts }
1055b50d3e8SMike Gerdts 
1065b50d3e8SMike Gerdts int
1075b50d3e8SMike Gerdts spdk_log_for_each_deprecation(void *ctx, spdk_log_for_each_deprecation_fn fn)
1085b50d3e8SMike Gerdts {
1095b50d3e8SMike Gerdts 	struct spdk_deprecation *dep;
1105b50d3e8SMike Gerdts 	int rc = 0;
1115b50d3e8SMike Gerdts 
1125b50d3e8SMike Gerdts 	TAILQ_FOREACH(dep, &g_deprecations, link) {
1135b50d3e8SMike Gerdts 		rc = fn(ctx, dep);
1145b50d3e8SMike Gerdts 		if (rc != 0) {
1155b50d3e8SMike Gerdts 			break;
1165b50d3e8SMike Gerdts 		}
1175b50d3e8SMike Gerdts 	}
1185b50d3e8SMike Gerdts 
1195b50d3e8SMike Gerdts 	return rc;
1205b50d3e8SMike Gerdts }
1215b50d3e8SMike Gerdts 
1225b50d3e8SMike Gerdts const char *
1235b50d3e8SMike Gerdts spdk_deprecation_get_tag(const struct spdk_deprecation *deprecation)
1245b50d3e8SMike Gerdts {
1255b50d3e8SMike Gerdts 	return deprecation->tag;
1265b50d3e8SMike Gerdts }
1275b50d3e8SMike Gerdts 
1285b50d3e8SMike Gerdts const char *
1295b50d3e8SMike Gerdts spdk_deprecation_get_description(const struct spdk_deprecation *deprecation)
1305b50d3e8SMike Gerdts {
1315b50d3e8SMike Gerdts 	return deprecation->desc;
1325b50d3e8SMike Gerdts }
1335b50d3e8SMike Gerdts 
1345b50d3e8SMike Gerdts const char *
1355b50d3e8SMike Gerdts spdk_deprecation_get_remove_release(const struct spdk_deprecation *deprecation)
1365b50d3e8SMike Gerdts {
1375b50d3e8SMike Gerdts 	return deprecation->remove;
1385b50d3e8SMike Gerdts }
1395b50d3e8SMike Gerdts 
1405b50d3e8SMike Gerdts uint64_t
1415b50d3e8SMike Gerdts spdk_deprecation_get_hits(const struct spdk_deprecation *deprecation)
1425b50d3e8SMike Gerdts {
1435b50d3e8SMike Gerdts 	return deprecation->hits;
1445b50d3e8SMike Gerdts }
145