dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.36k stars 4.74k forks source link

Exception Handling / Error Logging in English #40427

Open Chiramisu opened 4 years ago

Chiramisu commented 4 years ago

I have an application that is used in other countries. When receiving exception / error logs, they're invariably in other languages that I can't understand. I've looked into this, but had no luck. How do we force our C# .NET programs to log errors in English? If this currently isn't supported, please add it. I've seen requests for this around the Interwebz going back over a decade.

The user doesn't care about error logs. They are for developers; the vast majority of whom speak English.

svick commented 4 years ago

This is a duplicate of https://github.com/microsoft/dotnet/issues/474.

333fred commented 4 years ago

This isn't a language request, but rather a runtime request. I'm going to transfer this over there, and hopefully they'll have an answer or can point you in the right direction.

Dotnet-GitSync-Bot commented 4 years ago

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

Gnbrkm41 commented 4 years ago

Does .NET Core runtime itself do any localisation for the exception message? Most of the exception messages I'm seeing doesn't seem to be in my Windows UI language (Korean) and even if they are they seem to originate from Windows API or something.

ghost commented 4 years ago

Tagging subscribers to this area: @tarekgh, @safern, @krwq See info in area-owners.md if you want to be subscribed.

danmoseley commented 4 years ago

@ChirChiara what version of.NET are you using?.NET Core's own resources aren't currently localized.

What strings are getting logged and which code do they come from?

tarekgh commented 4 years ago

Also you can force English resources if you set CultureInfo.CurrentUICulture to something like en-US Culture. Also, you can use the machine translation to translate the localized string.

Chiramisu commented 4 years ago

For the record, I'm presently stuck with .NET Framework 3.5 on the app in question.

@333fred Thanks for moving it, I wasn't sure. @svick I think that duplicate you referenced may also be in the wrong area if indeed it is a duplicate.

@tarekgh I definitely don't want machine translation because that quickly becomes a game of "operator" where details can be lost in translation. Also, CultureInfo.CurrentUICulture does not work in my case because this did not become read-write until 4.6.

tarekgh commented 4 years ago

Also, CultureInfo.CurrentUICulture does not work in my case because this did not become read-write until 4.6.

You can use Thread.CurrentThread.CurrentUICulture instead. Also, you can set CultureInfo.DefaultThreadCurrentUICulture too to ensure other created threads later will get the english culture.

Side point, if you are talking about the full framework, then it is very unlikely such request will get added there. .NET core is our focus of future development and the full framework still supported but it is feature complete.

Chiramisu commented 4 years ago

Yes on the first point, no on the second. CultureInfo.DefaultThreadCurrentUICulture is not available in my version, and Thread.CurrentThread.CurrentUICulture comes with a security warning, but will probably be my only option for now.

I agree with you that my code base will inevitably need to be updated, and that is planned for the future, but even in modern versions of .NET I don't see this ability to declare Exceptions be loggable in the language of your choice. I want to maintain that my users see the errors in whatever language they prefer, but the logs are belong to me (intentional grammatical error) and I need them in English. 😋

tarekgh commented 4 years ago

CultureInfo.DefaultThreadCurrentUICulture is not available in my version

CultureInfo.DefaultThreadCurrentUICulture is supported since version 4.5. are you running on 4.0? if so, definitely you need to upgrade.

Chiramisu commented 4 years ago

3.5 SMH 🤦🏼‍♂️ Still trying to convince the PMs to let go of Windows XP support. 😫 I'm holding onto hope that we can finally do that on our next Major rev.

tarekgh commented 4 years ago

I hope you'll succeed with your mission :-)

do you mind if we close this issue as there is no action required here? feel free to send more questions if you need help with any issue you face.

Clockwork-Muse commented 4 years ago

I want to maintain that my users see the errors in whatever language they prefer, but the logs are belong to me (intentional grammatical error) and I need them in English.

... permanently set the UI culture as English, and then explicitly set the culture when doing all formatting/ToString()-ing? Although I'm not sure how that would affect some right-to-left text UI elements. Otherwise, are you saying that you're displaying raw exceptions to users?

Chiramisu commented 4 years ago

I don't believe I got an answer to my question though; or did I miss it? Does anything in the .NET multiverse natively support logging Exceptions (for Developer use) in English?

tarekgh commented 4 years ago

Does anything in the .NET multiverse natively support logging Exceptions (for Developer use) in English?

There is nothing you can do without forcing the UI language on the app/running environment to English to guarantee getting English. Does the exception messages you are getting are the framework messages or app messages?

Chiramisu commented 4 years ago

Framework of course. My app doesn't rely on any other third party APIs etc, so all app messages are written by me and already in English. It's the Framework that is generating Exceptions in the native culture of the client machine.

tarekgh commented 4 years ago

One other idea you may try is to uninstall the .NET Framework language packs from the machine. I don't have handy Windows XP machine but I believe you can do that from Control Panel, Add Or Remove programs options.

Zymlex commented 4 years ago

One other idea you may try is to uninstall the .NET Framework language packs from the machine.

🤦‍♂️ The use of implicit localization of the program, and even more of the localization of exceptions (which only developers see), was the most idiotic idea.

tarekgh commented 4 years ago

@Zymlex my suggestion was specific workaround for @Chiramisu case based on my question https://github.com/dotnet/runtime/issues/40427#issuecomment-670721303 and not intended to be for any situation. If you have any constructive feedback, please share it.

danmoseley commented 2 years ago

localization of exceptions (which only developers see)

That that's not true for all apps. I worked on a product that was itself localized and displayed system error messages to the user, for example if they chose an invalid directory and we got an IO exception, we would show the message like "Directory 'c:\foo' does not exist." This was useful and often times we could not get that detail without parsing the message ourselves (as an aside, IO error codes could have helped). The original reason .NET Framework localized these was probably something like that -- the messages would often appear at development time (eg., in the Windows Forms designer) and not all developers wish to use English. Visual Studio is localized and expects all strings to be localized.

That is why when we've discussed this problem in the past we've agreed that we'd likely need to offer an app-level flag to choose localized or not.

danmoseley commented 2 years ago

Is there a request here for .NET Core, given we do not localize? Eg., perhaps exception strings from another part of the .NET Core stack are localized?

If it is only for .NET Framework, we should close this. As mentioned, that will not be changed at this point. For .NET Core, if someday we do make it possible to get localized exception messages (i think there was another issue requesting that) it is clear that we should make it possible to choose.

cremor commented 2 years ago

This is a problem in .NET Core/5/6 with exception messages that are passed through from Windows. More details by @TobiasKnauss here: https://github.com/dotnet/runtime/issues/72277#issuecomment-1185810554

tarekgh commented 2 years ago

@cremor could you provide example of getting localized messages in Win32Exception? The exception class itself is not the issue but how the library using this exception class is getting the message from Windows. I expect this is not common cases anyway.

danmoseley commented 2 years ago

I guess this us when we get the message from FormatError (not sure whether strerror is localized). In that case so we even have a technical way to request English from the OS?

TobiasKnauss commented 2 years ago

@tarekgh To reproduce:

Console.WriteLine (new SocketException(10060).Message);

In my German Windows 10, I get a message in German language.

tarekgh commented 2 years ago

@TobiasKnauss thanks. Any idea if the issue is scoped to Win32Exception case? or seeing that in other scenarios?

I guess this us when we get the message from FormatError (not sure whether strerror is localized). In that case so we even have a technical way to request English from the OS?

Yes, we get the localized message from Windows when calling FormatMessage. This Windows API takes the dwLanguageId parameter. The current behavior is not the best because the returned localized message depends on the Thread language or Windows UI language which will not necessarily match the framework UI culture if the app decides to reset the UI culture.

If the issue for .NET is scoped to Win32Exception, we may try to think in a way to force English language when getting the message (like environment variable or something similar). But first I want to understand the demand on that and if it is really a blocking issue.

mlsomers commented 2 years ago

So Issue 474 got closed in favor of Issue 46656 which is now closed in favor of this one...

In my opinion it is certainly a blocking issue, it costs allot of extra resources and money to decrypt log files containing phrases like

The surgery is crippled while the opening is not switched on.

Back to

This operation is invalid while the window is disabled.

danmoseley commented 2 years ago

Can folks up vote @tarekgh answer above if it would address the problem to have a way to force .NET to request unlocalized (English) messages from the OS.

Note that .NET Core has never localized its own exception messages and .NET Framework requests are not tracked here.

mlsomers commented 2 years ago

If the issue for .NET is scoped to Win32Exception, we may try to think in a way to force English language when getting the message (like environment variable or something similar). But first I want to understand the demand on that and if it is really a blocking issue.

An environment variable would indeed be helpful for many scenarios (a +1 from me), however for desktop applications (winforms/wpf) it would be great if we could also set a flag for the current process from code. It would be even better if we can specify what we want after the exception is thrown (if possible).

I would like to suggest usingException.ToString(CultureInfo.InvariantCulture) or Exception.GetMessage(CultureInfo.InvariantCulture) to log in English and having the existing Exception.Message show the message in the language specified by System.Environment.ExceptionCulture which in turn gets its default value from an environment variable or registry setting or in another way that is at least configurable by an administrator without the need to recompile source. This way we can guarantee logs in English and still leave options open to the end user to have the dialog text in their own language or in English.

We often show dialog boxes with "something went wrong while... and the original error message was ..." for the rare occasion when users can solve issues themselves, but also to save our help-desk the need to dig into log-files...

danmoseley commented 2 years ago

It is too late to add new API to .NET 7 which is why I was asking about an environment variable as a possible temporary measure.

danmoseley commented 2 years ago

Cc @Ericstj as area owner.

TobiasKnauss commented 2 years ago

@tarekgh I have seen it only on Win32Exception so far, but I cannot tell whether it is limited to it.

If the issue for .NET is scoped to Win32Exception, we may try to think in a way to force English language when getting the message (like environment variable or something similar). But first I want to understand the demand on that and if it is really a blocking issue.

If you introduced an environment variable, this variable could be used to set the language if another language than English shall be used. But the default language should be English, so that it matches the language of all other .NET exceptions.

I don't know if this would be seen as a breaking change, since it does not include any API changes, which means every code will still compile. Problems may come up during execution though, if someone relies on the exceptions in their language. But to fix this, the mentioned environment variable could be used. There is one issue however that I see when using an environment variable: This variable applies to ALL applications. There will be no possibility to have one application return exception messages in English and another one return them in a different language. A process specific setting would be a better approach. If you decided to introduce an environment variable, it could be either a simple variable with general use, e.g. "DotNetExceptionLanguage" with values "en", "de", "fr" (or "en-us", de-de", "fr-fr"), etc., or a variable with detailed definition where to use which language, e.g. "DotNetAppSpecificExceptionLanguage" with a value like "c:\windows\notepad.exe?de-de|c:\windows\paint.exe?en-us" (I intentionally used ? and | as separators).

TobiasKnauss commented 2 years ago

@mlsomers I like the idea of having Exception.ToString(CultureInfo), however in my opinion, the usage of InvariantCulture (which is English most times) should return the same results as if no culture was specified (ToString()). This may contradict the concept where ToString() on other types (e.g. numbers like int, double, etc.) use CurrentCulture in their ToString() (e.g. (1.5).ToString() returns 1,5 (with comma) on my computer with German Windows. But the reason for this suggestion is, that the usage of exception messages in logs is far more common than displaying them to the user. I don't like rewriting thousands of lines of code, especially when implicit string conversions of exceptions (e.g. in string interpolation or concatenation) do not have an explicit .ToString() call and therefore are also hard to find. Also, a future localization of .NET exception messages will not be able to use ToString() for localized exception messages, because this would be the same kind of (non-breaking) change as mentioned in my previous comment, just the other way round. And I bet that app developers will wish .NET developers to hell if they "reverted" the exception messages language back to the local language, like in .NET Framework. ;-) Your suggested System.Environment.ExceptionCulture could solve this problem. I think it better fits in System.Globalization, but that is not important.

ghost commented 2 years ago

Tagging subscribers to this area: @dotnet/area-system-resources See info in area-owners.md if you want to be subscribed.

Issue Details
I have an application that is used in other countries. When receiving exception / error logs, they're invariably in other languages that I can't understand. I've looked into this, but had no luck. How do we force our C# .NET programs to log errors in English? If this currently isn't supported, please add it. I've seen requests for this around the Interwebz going back over a decade. The user doesn't care about error logs. They are for developers; the vast majority of whom speak English.
Author: Chiramisu
Assignees: -
Labels: `question`, `area-System.Resources`
Milestone: Future
ericstj commented 2 years ago

~~ For Exception.ToString(CultureInfo) can you do this, using @AaronRobinsonMSFT's new API? ~~

The workaround shared previously did not work well. A new workaround is here https://gist.github.com/ericstj/c72b90b0c12f86b7918850ee276fac3b but will only work if the Windows machine is English or has the English language pack installed.

tarekgh commented 2 years ago

@ericstj I am not sure if the proposed code is going to work. Windows depends on the thread locale. Setting Thread.CurrentThread.CurrentCulture is not going to affect Windows thread locale as I understand.

ericstj commented 2 years ago

I see, so instead of that we'd need to PINvoke to SetThreadLocale, maybe I can update the sample.

AaronRobinsonMSFT commented 2 years ago

@tarekgh Did we miss an opportunity here to create a culture overload for that API?

public static class Marshal
{
    public static string GetPInvokeErrorMessage(int error, CultureInfo cultureInfo);
}
ericstj commented 2 years ago

Adding that overload might be interesting. It would have made this extension method easier to implement. Updated my sample above to use SetThreadLocale (note it requires the new source generator as well). Still not sure if this is actually changing the behavior of FormatMessage. At this point one could just as well have the extensions method call FormatMessage itself.

tarekgh commented 2 years ago

I see, so instead of that we'd need to PINvoke to SetThreadLocale, maybe I can update the sample.

Yes, I think this will work.

Did we miss an opportunity here to create a culture overload for that API?

I think such overload will be helpful.

AaronRobinsonMSFT commented 2 years ago

@tarekgh and @ericstj Filed https://github.com/dotnet/runtime/issues/72546 for .NET 8

/cc @danmoseley

tarekgh commented 2 years ago

I just learned that Windows localized machines is not guaranteed to have English resources. For such situation there will not be anyway getting the English resources with Win32Exeption.

AaronRobinsonMSFT commented 2 years ago

@tarekgh Should we then close the API proposal? I think we are in a situation we can't win.

TobiasKnauss commented 2 years ago

I just learned that Windows localized machines is not guaranteed to have English resources. For such situation there will not be anyway getting the English resources with Win32Exeption.

This means we may create a request for the Windows development team, aiming at always including English resources.

tfenise commented 2 years ago

To reproduce:

Console.WriteLine (new SocketException(10060).Message);

In my German Windows 10, I get a message in German language.

However, new SocketException(10060).ToString() starts with "System.Net.Sockets.SocketException (10060):", whatever the language in which the following message is in. Is that not helpful enough?

cremor commented 2 years ago

@tfenise Are we expected to know or look up the error codes? If yes, is there a central page of all possible error codes?

Even if the answer is yes, that's still way more work to figure out the actual error when you have to read through a log file.

tfenise commented 2 years ago

In the case of SocketException, the developer can just run new SocketException(10060).ToString() on their own machine (or write a program that looks for System.Net.Sockets.SocketException (###): in a log file and insert the error message in the preferred language) and see what the error code means. If this is still unsatisfactory, I think SocketException.ToString() (or Win32Exception.ToString()) can be modified to include not only the decimal or hexadecimal printing of the error code, but also Enum.GetName<SocketError>(the_error_code), which would be "TimedOut" for 10060. This change is certainly easier than adding some new API or even change in Windows localization.

cremor commented 2 years ago

In the case of SocketException, the developer can just run new SocketException(10060).ToString() on their own machine (or write a program that looks for System.Net.Sockets.SocketException (###): in a log file and insert the error message in the preferred language) and see what the error code means.

That would still be a manual step. Not very convenient.

If this is still unsatisfactory, I think SocketException.ToString() (or Win32Exception.ToString()) can be modified to include not only the decimal or hexadecimal printing of the error code, but also Enum.GetName<SocketError>(the_error_code), which would be "TimedOut" for 10060. This change is certainly easier than adding some new API or even change in Windows localization.

That would certainly be a quick win that should be done.

danmoseley commented 2 years ago

If this is still unsatisfactory, I think SocketException.ToString() (or Win32Exception.ToString()) can be modified to include not only the decimal or hexadecimal printing of the error code, but also Enum.GetName(the_error_code), which would be "TimedOut" for 10060. This change is certainly easier than adding some new API or even change in Windows localization.

Please open an issue if you want to suggest that for SocketException. It does sound useful. I do not see how it would work for Win32Exception though, there is no enum (such an enum would be vast, eg., it would be all of winerror.h, etc)