Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: print unretrieved global error messages #4005

Merged
merged 1 commit into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/include/OpenImageIO/imageio.h
Original file line number Diff line number Diff line change
Expand Up @@ -2980,6 +2980,21 @@ OIIO_API std::string geterror(bool clear = true);
/// the log information. When the `log_times` attribute is disabled,
/// there is no additional performance cost.
///
/// - `oiio:print_uncaught_errors` (1)
///
/// If nonzero, upon program exit, any error messages that would have been
/// retrieved by a call to `OIIO::geterror()`, but never were, will be
/// printed to stdout. While this may seem chaotic, we are presuming that
/// any well-written library or application will proactively check error
/// codes and retrieve errors, so this will never print anything upon exit.
/// But for less sophisticated applications (or users), this is very useful
/// for forcing display of error messages so that users can see relevant
/// errors even if they never check them explicitly, thus self-diagnose
/// their troubles before asking the project dev deam for help. Advanced
/// users who for some reason desire to neither retrieve errors themselves
/// nor have them printed in this manner can disable the behavior by setting
/// this attribute to 0.
///
/// - `imagebuf:print_uncaught_errors` (1)
///
/// If nonzero, an `ImageBuf` upon destruction will print any error messages
Expand Down
34 changes: 33 additions & 1 deletion src/libOpenImageIO/imageio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ std::string output_format_list; // comma-separated list of writable formats
std::string extension_list; // list of all extensions for all formats
std::string library_list; // list of all libraries for all formats
int oiio_log_times = Strutil::stoi(Sysutil::getenv("OPENIMAGEIO_LOG_TIMES"));
int oiio_print_uncaught_errors(1);
std::vector<float> oiio_missingcolor;
} // namespace pvt

Expand Down Expand Up @@ -225,9 +226,29 @@ openimageio_version()



// ErrorHolder houses a string, with the addition that when it is destroyed,
// it will disgorge any un-retrieved error messages, in an effort to help
// beginning users diagnose their problems if they have forgotten to call
// geterror().
struct ErrorHolder {
std::string error_msg;

~ErrorHolder()
{
if (!error_msg.empty() && pvt::oiio_print_uncaught_errors) {
OIIO::print(
"OpenImageIO exited with a pending error message that was never\n"
"retrieved via OIIO::geterror(). This was the error message:\n{}\n",
error_msg);
}
}
};



// To avoid thread oddities, we have the storage area buffering error
// messages for append_error()/geterror() be thread-specific.
static thread_local std::string error_msg;
static thread_local ErrorHolder error_msg_holder;


void
Expand All @@ -236,6 +257,7 @@ pvt::append_error(string_view message)
// Remove a single trailing newline
if (message.size() && message.back() == '\n')
message.remove_suffix(1);
std::string& error_msg(error_msg_holder.error_msg);
OIIO_ASSERT(
error_msg.size() < 1024 * 1024 * 16
&& "Accumulated error messages > 16MB. Try checking return codes!");
Expand All @@ -256,6 +278,7 @@ pvt::append_error(string_view message)
bool
has_error()
{
std::string& error_msg(error_msg_holder.error_msg);
return !error_msg.empty();
}

Expand All @@ -264,6 +287,7 @@ has_error()
std::string
geterror(bool clear)
{
std::string& error_msg(error_msg_holder.error_msg);
std::string e = error_msg;
if (clear)
error_msg.clear();
Expand Down Expand Up @@ -344,6 +368,10 @@ attribute(string_view name, TypeDesc type, const void* val)
limit_imagesize_MB = *(const int*)val;
return true;
}
if (name == "oiio:print_uncaught_errors" && type == TypeInt) {
oiio_print_uncaught_errors = *(const int*)val;
return true;
}
if (name == "imagebuf:print_uncaught_errors" && type == TypeInt) {
imagebuf_print_uncaught_errors = *(const int*)val;
return true;
Expand Down Expand Up @@ -480,6 +508,10 @@ getattribute(string_view name, TypeDesc type, void* val)
*(int*)val = dds_bc5normal;
return true;
}
if (name == "oiio:print_uncaught_errors" && type == TypeInt) {
*(int*)val = oiio_print_uncaught_errors;
return true;
}
if (name == "imagebuf:print_uncaught_errors" && type == TypeInt) {
*(int*)val = imagebuf_print_uncaught_errors;
return true;
Expand Down
1 change: 1 addition & 0 deletions src/libtexture/imagecache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2721,6 +2721,7 @@ ImageCacheImpl::get_image_info(ImageCacheFile* file,
std::string* errptr = m_errormessage.get();
if (errptr)
errptr->clear();
(void)OIIO::geterror(true); // Suppress global errors
}
return true;
}
Expand Down
5 changes: 5 additions & 0 deletions src/oiiotool/oiiotool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5285,6 +5285,11 @@ input_file(Oiiotool& ot, cspan<const char*> argv)
auto input = ImageInput::create(filename);
if (input && input->supports("procedural"))
exists = 1;
if (!input) {
// If the create call failed, eat any stray global errors it
// may have issued.
(void)OIIO::geterror();
}
}
ImageBufRef substitute; // possible substitute for missing image
if (!exists) {
Expand Down