Updated Branches: refs/heads/consistent-errors [created] 42306ff72
TS-2106 steal "api" from gzip plugin because we really, really like the logging API in gzip plugin because it's very detailed. Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/7facd11d Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/7facd11d Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/7facd11d Branch: refs/heads/consistent-errors Commit: 7facd11d03870f8c19ecab955f1b8504021f1daf Parents: aeea92c Author: Igor GaliÄ <i.ga...@brainsware.org> Authored: Thu Aug 8 15:58:43 2013 +0200 Committer: Igor GaliÄ <i.ga...@brainsware.org> Committed: Sun Aug 11 20:13:03 2013 +0200 ---------------------------------------------------------------------- plugins/gzip/configuration.cc | 12 +++--- plugins/gzip/debug_macros.h | 28 +------------- plugins/gzip/gzip.cc | 76 +++++++++++++++++++------------------- plugins/gzip/misc.cc | 12 +++--- proxy/api/ts/debug.h | 71 +++++++++++++++++++++++++++++++++++ proxy/api/ts/ts.h.in | 1 + 6 files changed, 124 insertions(+), 76 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7facd11d/plugins/gzip/configuration.cc ---------------------------------------------------------------------- diff --git a/plugins/gzip/configuration.cc b/plugins/gzip/configuration.cc index 5e69c5c..98fd91b 100644 --- a/plugins/gzip/configuration.cc +++ b/plugins/gzip/configuration.cc @@ -118,7 +118,7 @@ namespace Gzip { for (size_t i = 0; i < disallows_.size(); i++) { if ( fnmatch (disallows_[i].c_str(), surl.c_str(), 0) == 0 ) { - info("url [%s] disabled for compression, matched on pattern [%s]", + TSLogInfo("URL [%s] disabled for compression, matched on pattern [%s]", surl.c_str(), disallows_[i].c_str()); return false; } @@ -138,7 +138,7 @@ namespace Gzip { match_string++;//skip '!' } if ( fnmatch (match_string, scontent_type.c_str(), 0) == 0 ) { - info("compressible content type [%s], matched on pattern [%s]", + TSLogInfo("compressible content type [%s], matched on pattern [%s]", scontent_type.c_str(), compressible_content_types_[i].c_str()); is_match = !exclude; } @@ -169,7 +169,7 @@ namespace Gzip { } path = pathstring.c_str(); - info("Parsing file \"%s\"", path); + TSLogInfo("Parsing file \"%s\"", path); std::ifstream f; size_t lineno = 0; @@ -177,7 +177,7 @@ namespace Gzip { f.open(path, std::ios::in); if (!f.is_open()) { - warning("could not open file [%s], skip",path); + TSLogWarning("could not open file [%s], skip",path); return c; } @@ -223,7 +223,7 @@ namespace Gzip { state = kParseDisallow; } else { - warning("failed to interpret \"%s\" at line %zu", token.c_str(), lineno); + TSLogWarning("failed to interpret \"%s\" at line %zu", token.c_str(), lineno); } break; case kParseCompressibleContentType: @@ -251,7 +251,7 @@ namespace Gzip { } if (state != kParseStart) { - warning("the parser state indicates that data was expected when it reached the end of the file (%d)", state); + TSLogWarning("the parser state indicates that data was expected when it reached the end of the file (%d)", state); } return c; http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7facd11d/plugins/gzip/debug_macros.h ---------------------------------------------------------------------- diff --git a/plugins/gzip/debug_macros.h b/plugins/gzip/debug_macros.h index 151de31..084c788 100644 --- a/plugins/gzip/debug_macros.h +++ b/plugins/gzip/debug_macros.h @@ -24,32 +24,8 @@ #ifndef _DBG_MACROS_H #define _DBG_MACROS_H -#include <ts/ts.h> - -#define TAG "gzip" - -#define debug(fmt, args...) do { \ - TSDebug(TAG, "DEBUG: [%s:%d] [%s] " fmt, __FILE__, __LINE__, __FUNCTION__ , ##args ); \ - } while (0) - -#define info(fmt, args...) do { \ - TSDebug(TAG, "INFO: " fmt, ##args ); \ - } while (0) - -#define warning(fmt, args...) do { \ - TSDebug(TAG, "WARNING: " fmt, ##args ); \ -} while (0) - -#define error(fmt, args...) do { \ - TSError("[%s:%d] [%s] ERROR: " fmt, __FILE__, __LINE__, __FUNCTION__ , ##args ); \ - TSDebug(TAG, "[%s:%d] [%s] ERROR: " fmt, __FILE__, __LINE__, __FUNCTION__ , ##args ); \ -} while (0) - -#define fatal(fmt, args...) do { \ - TSError("[%s:%d] [%s] ERROR: " fmt, __FILE__, __LINE__, __FUNCTION__ , ##args ); \ - TSDebug(TAG, "[%s:%d] [%s] ERROR: " fmt, __FILE__, __LINE__, __FUNCTION__ , ##args ); \ - exit(-1); \ -} while (0) +#define PLUGIN_NAME "gzip" +#include <ts/debug.h> //FIXME: this one doesn't deserve to be here #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7facd11d/plugins/gzip/gzip.cc ---------------------------------------------------------------------- diff --git a/plugins/gzip/gzip.cc b/plugins/gzip/gzip.cc index 9c84dc8..c0d0c28 100644 --- a/plugins/gzip/gzip.cc +++ b/plugins/gzip/gzip.cc @@ -87,13 +87,13 @@ gzip_data_alloc(int compression_type) err = deflateInit2(&data->zstrm, ZLIB_COMPRESSION_LEVEL, Z_DEFLATED, window_bits, ZLIB_MEMLEVEL, Z_DEFAULT_STRATEGY); if (err != Z_OK) { - fatal("gzip-transform: ERROR: deflateInit (%d)!", err); + TSLogFatal("gzip-transform: deflateInit (%d)!", err); } if (dictionary) { err = deflateSetDictionary(&data->zstrm, (const Bytef *) dictionary, strlen(dictionary)); if (err != Z_OK) { - fatal("gzip-transform: ERROR: deflateSetDictionary (%d)!", err); + TSLogFatal("gzip-transform: deflateSetDictionary (%d)!", err); } } @@ -138,7 +138,7 @@ gzip_content_encoding_header(TSMBuffer bufp, TSMLoc hdr_loc, const int compressi } if (ret != TS_SUCCESS) { - error("cannot add the Content-Encoding header"); + TSLogError("cannot add the Content-Encoding header"); } return ret; @@ -179,7 +179,7 @@ gzip_vary_header(TSMBuffer bufp, TSMLoc hdr_loc) } if (ret != TS_SUCCESS) { - error("cannot add/update the Vary header"); + TSLogError("cannot add/update the Vary header"); } return ret; @@ -213,7 +213,7 @@ gzip_etag_header(TSMBuffer bufp, TSMLoc hdr_loc) } if (ret != TS_SUCCESS) { - error("cannot handle the %s header", TS_MIME_FIELD_ETAG); + TSLogError("cannot handle the %s header", TS_MIME_FIELD_ETAG); } return ret; @@ -233,7 +233,7 @@ gzip_transform_init(TSCont contp, GzipData * data) data->state = transform_state_output; if (TSHttpTxnTransformRespGet(data->txn, &bufp, &hdr_loc) != TS_SUCCESS) { - error("Error TSHttpTxnTransformRespGet"); + TSLogError("TSHttpTxnTransformRespGet"); return; } @@ -263,13 +263,13 @@ gzip_transform_one(GzipData * data, TSIOBufferReader upstream_reader, int amount while (amount > 0) { downstream_blkp = TSIOBufferReaderStart(upstream_reader); if (!downstream_blkp) { - error("couldn't get from IOBufferBlock"); + TSLogError("could not get from IOBufferBlock"); return; } upstream_buffer = TSIOBufferBlockReadStart(downstream_blkp, upstream_reader, &upstream_length); if (!upstream_buffer) { - error("couldn't get from TSIOBufferBlockReadStart"); + TSLogError("could not get from TSIOBufferBlockReadStart"); return; } @@ -290,7 +290,7 @@ gzip_transform_one(GzipData * data, TSIOBufferReader upstream_reader, int amount err = deflate(&data->zstrm, Z_NO_FLUSH); if (err != Z_OK) - warning("deflate() call failed: %d", err); + TSLogWarning("deflate() call failed: %d", err); if (downstream_length > data->zstrm.avail_out) { TSIOBufferProduce(data->downstream_buffer, downstream_length - data->zstrm.avail_out); @@ -299,7 +299,7 @@ gzip_transform_one(GzipData * data, TSIOBufferReader upstream_reader, int amount if (data->zstrm.avail_out > 0) { if (data->zstrm.avail_in != 0) { - error("gzip-transform: ERROR: avail_in is (%d): should be 0", data->zstrm.avail_in); + TSLogError("gzip-transform: ERROR: avail_in is (%d): should be 0", data->zstrm.avail_in); } } } @@ -339,13 +339,13 @@ gzip_transform_finish(GzipData * data) } if (err != Z_STREAM_END) { - warning("deflate should report Z_STREAM_END"); + TSLogWarning("deflate should report Z_STREAM_END"); } break; } if (data->downstream_length != (int64_t) (data->zstrm.total_out)) { - error("gzip-transform: ERROR: output lengths don't match (%d, %ld)", data->downstream_length, + TSLogError("gzip-transform: output lengths don't match (%d, %ld)", data->downstream_length, data->zstrm.total_out); } @@ -427,7 +427,7 @@ gzip_transform(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */) } else { switch (event) { case TS_EVENT_ERROR:{ - debug("gzip_transform: TS_EVENT_ERROR starts"); + TSLogDebug("gzip_transform: TS_EVENT_ERROR starts"); TSVIO upstream_vio = TSVConnWriteVIOGet(contp); TSContCall(TSVIOContGet(upstream_vio), TS_EVENT_ERROR, upstream_vio); } @@ -442,7 +442,7 @@ gzip_transform(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */) gzip_transform_do(contp); break; default: - warning("unknown event [%d]", event); + TSLogWarning("unknown event [%d]", event); gzip_transform_do(contp); break; } @@ -480,7 +480,7 @@ gzip_transformable(TSHttpTxn txnp, int server, HostConfiguration * host_configur //conservatively pick some statusses to compress if (!(resp_status == 200 || resp_status == 404 || resp_status == 500)) { - info("http response status [%d] is not compressible", resp_status); + TSLogInfo("http response status [%d] is not compressible", resp_status); return 0; } @@ -490,7 +490,7 @@ gzip_transformable(TSHttpTxn txnp, int server, HostConfiguration * host_configur int method_length; const char *method = TSHttpHdrMethodGet(cbuf, chdr, &method_length); if (!(method_length == TS_HTTP_LEN_GET && memcmp(method, TS_HTTP_METHOD_GET, TS_HTTP_LEN_GET) == 0)) { - debug("method is not GET, not compressible"); + TSLogDebug("method is not GET, not compressible"); TSHandleMLocRelease(cbuf, TS_NULL_MLOC, chdr); return 0; } @@ -520,11 +520,11 @@ gzip_transformable(TSHttpTxn txnp, int server, HostConfiguration * host_configur TSHandleMLocRelease(cbuf, TS_NULL_MLOC, chdr); if (!compression_acceptable) { - info("no acceptable encoding found in request header, not compressible"); + TSLogInfo("no acceptable encoding found in request header, not compressible"); return 0; } } else { - info("no acceptable encoding found in request header, not compressible"); + TSLogInfo("no acceptable encoding found in request header, not compressible"); TSHandleMLocRelease(cbuf, chdr, cfield); TSHandleMLocRelease(cbuf, TS_NULL_MLOC, chdr); return 0; @@ -540,7 +540,7 @@ gzip_transformable(TSHttpTxn txnp, int server, HostConfiguration * host_configur to do anything. */ field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_CONTENT_ENCODING, -1); if (field_loc) { - info("response is already content encoded, not compressible"); + TSLogInfo("response is already content encoded, not compressible"); TSHandleMLocRelease(bufp, hdr_loc, field_loc); TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); return 0; @@ -550,7 +550,7 @@ gzip_transformable(TSHttpTxn txnp, int server, HostConfiguration * host_configur content type of "text/" or "application/x-javascript". */ field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_CONTENT_TYPE, -1); if (!field_loc) { - info("no content type header found, not compressible"); + TSLogInfo("no content type header found, not compressible"); TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); return 0; } @@ -559,7 +559,7 @@ gzip_transformable(TSHttpTxn txnp, int server, HostConfiguration * host_configur int rv = host_configuration->ContentTypeIsCompressible(value, len); if (!rv) { - info("content-type [%.*s] not compressible", len, value); + TSLogInfo("content-type [%.*s] not compressible", len, value); } TSHandleMLocRelease(bufp, hdr_loc, field_loc); TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); @@ -573,11 +573,11 @@ gzip_transform_add(TSHttpTxn txnp, int /* server ATS_UNUSED */, HostConfiguratio int *tmp = (int *) TSHttpTxnArgGet(txnp, arg_idx_hooked); if (tmp) { //happens on cache_stale_hit - debug("transform hook already set, bail"); + TSLogDebug("transform hook already set, bail"); return; } else { TSHttpTxnArgSet(txnp, arg_idx_hooked, (void *) &GZIP_ONE); - info("adding compression transform"); + TSLogInfo("adding compression transform"); } TSHttpTxnUntransformedRespCache(txnp, 1); @@ -605,15 +605,15 @@ cache_transformable(TSHttpTxn txnp) int obj_status; if (TSHttpTxnCacheLookupStatusGet(txnp, &obj_status) == TS_ERROR) { - warning("Couldn't get cache status of object"); + TSLogWarning("Couldn't get cache status of object"); return 0; } if (obj_status == TS_CACHE_LOOKUP_HIT_STALE) { - info("stale cache hit"); + TSLogInfo("stale cache hit"); return 0; } if (obj_status == TS_CACHE_LOOKUP_HIT_FRESH) { - info("fresh cache hit"); + TSLogInfo("fresh cache hit"); return 1; } @@ -659,7 +659,7 @@ transform_plugin(TSCont /* contp ATS_UNUSED */, TSEvent event, void *edata) if (!hc->enabled() || !hc->IsUrlAllowed(url, url_len)) { //FIXME: no double negatives TSHttpTxnArgSet(txnp, arg_idx_url_disallowed, (void *) &GZIP_ONE); - info("url [%.*s] not allowed", url_len, url); + TSLogInfo("url [%.*s] not allowed", url_len, url); } else { normalize_accept_encoding(txnp, req_buf, req_loc); } @@ -725,7 +725,7 @@ transform_plugin(TSCont /* contp ATS_UNUSED */, TSEvent event, void *edata) break; default: - fatal("gzip transform unknown event"); + TSLogFatal("gzip transform unknown event"); } return 0; @@ -738,7 +738,7 @@ read_configuration(TSCont contp) { Configuration * newconfig = Configuration::Parse(path); Configuration * oldconfig =__sync_lock_test_and_set(&config, newconfig); - debug("config swapped,old config %p", oldconfig); + TSLogDebug("config swapped,old config %p", oldconfig); //FIXME: we have leaked. //consider cloning or refcounting the configuration passed to the txn @@ -751,7 +751,7 @@ static int management_update(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */) { TSReleaseAssert(event == TS_EVENT_MGMT_UPDATE); - info("management update event received"); + TSLogInfo("management update event received"); read_configuration(contp); return 0; } @@ -763,15 +763,15 @@ TSPluginInit(int argc, const char *argv[]) string config_path; if (argc > 2) { - fatal("the gzip plugin does not accept more than 1 plugin argument"); + TSLogFatal("the gzip plugin does not accept more than 1 plugin argument"); } else if (argc == 2) { config_path = std::string(argv[1]); } - info("TSPluginInit %s", argv[0]); + TSLogInfo("TSPluginInit %s", argv[0]); if (!register_plugin()) { - fatal("The gzip plugin failed to register"); + TSLogFatal("The gzip plugin failed to register"); } //if (argc == 2) { @@ -779,13 +779,13 @@ TSPluginInit(int argc, const char *argv[]) //} if (TSHttpArgIndexReserve("gzip", "for remembering if the hook was set", &arg_idx_hooked) != TS_SUCCESS) { - fatal("failed to reserve an argument index"); + TSLogFatal("failed to reserve an argument index"); } if (TSHttpArgIndexReserve("gzip", "for storing if compression is applicable", &arg_idx_host_configuration) != TS_SUCCESS) { - fatal("failed to reserve an argument index"); + TSLogFatal("failed to reserve an argument index"); } if (TSHttpArgIndexReserve("gzip", "for storing if compression is disallowed for this txn", &arg_idx_url_disallowed) != TS_SUCCESS) { - fatal("failed to reserve an argument index"); + TSLogFatal("failed to reserve an argument index"); } global_hidden_header_name = init_hidden_header_name(); @@ -795,7 +795,7 @@ TSPluginInit(int argc, const char *argv[]) char * p = (char*)TSmalloc(config_path.size()+1); strcpy(p,config_path.c_str()); TSContDataSet(management_contp,(void*)p); - TSMgmtUpdateRegister(management_contp, TAG); + TSMgmtUpdateRegister(management_contp, PLUGIN_NAME); read_configuration(management_contp); TSCont transform_contp = TSContCreate(transform_plugin, NULL); @@ -804,5 +804,5 @@ TSPluginInit(int argc, const char *argv[]) TSHttpHookAdd(TS_HTTP_SEND_REQUEST_HDR_HOOK, transform_contp); TSHttpHookAdd(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, transform_contp); - info("loaded"); + TSLogInfo("loaded"); } http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7facd11d/plugins/gzip/misc.cc ---------------------------------------------------------------------- diff --git a/plugins/gzip/misc.cc b/plugins/gzip/misc.cc index 13f9d39..63b42a7 100644 --- a/plugins/gzip/misc.cc +++ b/plugins/gzip/misc.cc @@ -83,10 +83,10 @@ normalize_accept_encoding(TSHttpTxn /* txnp ATS_UNUSED */, TSMBuffer reqp, TSMLo if (gzip) { TSMimeHdrFieldValueStringInsert(reqp, hdr_loc, field, -1, "gzip", strlen("gzip")); - info("normalized accept encoding to gzip"); + TSLogInfo("normalized accept encoding to gzip"); } else if (deflate) { TSMimeHdrFieldValueStringInsert(reqp, hdr_loc, field, -1, "deflate", strlen("deflate")); - info("normalized accept encoding to deflate"); + TSLogInfo("normalized accept encoding to deflate"); } TSMimeHdrFieldAppend(reqp, hdr_loc, field); @@ -129,7 +129,7 @@ init_hidden_header_name() TSMgmtString result; if (TSMgmtStringGet(var_name, &result) != TS_SUCCESS) { - fatal("failed to get server name"); + TSLogFatal("failed to get server name"); } else { int hidden_header_name_len = strlen("x-accept-encoding-") + strlen(result); hidden_header_name = (char *) TSmalloc(hidden_header_name_len + 1); @@ -166,7 +166,7 @@ load_dictionary(const char *preload_file) fp = fopen(preload_file, "r"); if (!fp) { - fatal("gzip-transform: ERROR: Unable to open dict file %s", preload_file); + TSLogFatal("gzip-transform: Unable to open dict file %s", preload_file); } /* dict = (char *) calloc(8000, sizeof(char)); */ @@ -190,8 +190,8 @@ void gzip_log_ratio(int64_t in, int64_t out) { if (in) { - info("Compressed size %" PRId64" (bytes), Original size %" PRId64", ratio: %f", out, in, ((float) (in - out) / in)); + TSLogInfo("Compressed size %" PRId64" (bytes), Original size %" PRId64", ratio: %f", out, in, ((float) (in - out) / in)); } else { - debug("Compressed size %" PRId64" (bytes), Original size %" PRId64", ratio: %f", out, in, 0.0F); + TSLogDebug("Compressed size %" PRId64" (bytes), Original size %" PRId64", ratio: %f", out, in, 0.0F); } } http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7facd11d/proxy/api/ts/debug.h ---------------------------------------------------------------------- diff --git a/proxy/api/ts/debug.h b/proxy/api/ts/debug.h new file mode 100644 index 0000000..7e0854e --- /dev/null +++ b/proxy/api/ts/debug.h @@ -0,0 +1,71 @@ +/** @file + + Traffic Server SDK API header file for debug messages + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + + @section developers Developers + + */ + +#ifndef __TS_DEBUG_H__ +#define __TS_DEBUG_H__ + +#include <ts/ts.h> + +/** all of these APIs assume you've defined PLUGIN_NAME first before + * including this header file. + * + * These APIs are private, that is: They are not installed. They + * can be used by in-tree plugins, external plugins will have to redefine this + * or find their own way of logging, until ATS has unified it's plugin logging + * in the same way it has unified the core-logging. + **/ + +#ifndef PLUGIN_NAME +# error "A plugin must define a PLUGIN_NAME string constant *before* including <ts/ts.h> in order to use TSLog(Debug|Info|Warning|Error|Fatal)" +#else + +#define TSLogDebug(fmt, args...) do { \ + TSDebug(PLUGIN_NAME, "DEBUG: [%s:%d] [%s] " fmt, __FILE__, __LINE__, __func__ , ##args ); \ + } while (0) + +#define TSLogInfo(fmt, args...) do { \ + TSDebug(PLUGIN_NAME, "INFO: " fmt, ##args ); \ + } while (0) + +#define TSLogWarning(fmt, args...) do { \ + TSDebug(PLUGIN_NAME, "WARNING: " fmt, ##args ); \ +} while (0) + +#define TSLogError(fmt, args...) do { \ + TSError("[%s] [%s:%d] [%s] ERROR: " fmt, PLUGIN_NAME, __FILE__, __LINE__, __func__ , ##args ); \ + TSDebug(PLUGIN_NAME, "[%s:%d] [%s] ERROR: " fmt, __FILE__, __LINE__, __func__ , ##args ); \ +} while (0) +#endif + +#define TSLogFatal(fmt, args...) do { \ + TSError("[%s] [%s:%d] [%s] FATAL: " fmt, PLUGIN_NAME, __FILE__, __LINE__, __func__ , ##args ); \ + TSDebug(PLUGIN_NAME, "[%s:%d] [%s] FATAL: " fmt, __FILE__, __LINE__, __func__ , ##args ); \ + exit(-1); \ +} while (0) + + +# endif /* __TS_DEBUG_H__ */ + http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7facd11d/proxy/api/ts/ts.h.in ---------------------------------------------------------------------- diff --git a/proxy/api/ts/ts.h.in b/proxy/api/ts/ts.h.in index 3379a26..7da91d7 100644 --- a/proxy/api/ts/ts.h.in +++ b/proxy/api/ts/ts.h.in @@ -1300,6 +1300,7 @@ extern "C" */ tsapi void TSError(const char* fmt, ...) TS_PRINTFLIKE(1, 2); + /* -------------------------------------------------------------------------- Assertions */ tsapi void _TSReleaseAssert(const char* txt, const char* f, int l) TS_NORETURN;