This question already has answers here:
Avoid `print` calls in production code. (Documentation)
(6 answers)
Closed 4 months ago.
My code keeps giving me a warning...
Avoid print calls in production code.
How do I resolve it?
Use debugPrint instead. Just know that debugPrint can only take a String? so you might need to use toString() or correctly format the data you are trying to display.
import 'package:flutter/foundation.dart';
debugPrint('This is a debugPrint');
You can use print statement in only debug mode when app run in release mode print statement avoid. Write print using below both method:-
import 'package:flutter/foundation.dart';
if (kDebugMode) {
print("Hello");
}
OR
debugPrint('This is a debugPrint');
Print() is a function which helps you in debugging process, it's not a good idea to use it unconditionally, you may leak some sensitive information in Release version of your app
It's better to make sure that you're using this function in Debug mode
There are some options:
Using debugPrint() instead of print()
debugPrint('some debug info ...')
Using assert() function which will be called in Debug mode only
assert(() {
print('some debug info ...');
return true;
});
Checking Debug Mode before using print()
import 'package:flutter/foundation.dart';
...
if (kDebugMode) {
print('some debug info ...');
}
If you're sure that you have enough control on using print() function, you can ignore that warning by using ignore directive :
Use this on top of the file : // ignore_for_file: avoid_print
Or add this line before print() function
// ignore: avoid_print
print('some debug info ...');
To ignore that warning for the whole project, you can add this lines to analysis_options.yaml file of the project :
include: package:flutter_lints/flutter.yaml
linter:
rules:
avoid_print: false
Related
I have deployed my flutter app and one user says that a certain part is not working. Therefore, I am interested in finding a way to write all output that usually gets dumped to the console to a string. I could then send this string to myself and use it to debug the problem.
Is there a way to subscribe to all console output? I found runZoned(() => ...) but this seems to only collect certain logs and especially no logs from other isolates.
In theory, it's possible to capture all log output and then store it as a variable. In practice, it's a lot of work and will likely require elevated privileges to access the log stream from within the app itself (which might not even be possible on iOS without a rooted device).
However, I propose that you flip the equation - instead of retrieving the log output, capture your logs before they make it to the console in the first place.
This is where packages such as logger shine. By routing all of your print statements through a logging service, you can set up middleware that will capture your output on the way through the pipe. This way, you can store all of the output without having to mess with things like OS permissions and privileges.
final buffer = BufferOutput();
final logger = Logger(output: buffer);
class BufferOutput extends LogOutput {
final lines = <String>[];
#override
void output(OutputEvent event) {
lines.addAll(event.lines);
for (var line in event.lines) {
print(line);
}
}
}
Usage:
logger.v("This is verbose text");
logger.d("This is debug text");
logger.i("This is info text");
logger.w("This is warning text");
logger.e("This is error text");
logger.wtf("This is what-the-fudgestickles text");
print(buffer.lines);
// Output:
// ["This is verbose text","This is debug text","This is info text","This is warning text","This is error text","This is what-the-fudgestickles text"]
Note: This will work if you want to capture normal app logging output. If you want to automatically capture exceptional log output, you are better off using something like Crashlytics or Sentry to capture and collate those error logs for you since, depending on the error, you can't depend on your app code to be able to run after the error happens anyway.
There is some confusion when to use print and debugPrint, so there are some statements which may be false, and which should be clearified:
When using the direct print method then it will bring a lot of a trash into production, will not it?
When using the debugPrint method then it will print only while developing, or it will print also in production?
When I generate a release file (apk), will not it delete all the print calls to optimize the app and reduce the release file size?
and 3. If you use the command flutter logs you will see the output of the print function in all applications you have installed in the phone/emulator. This means that even if the app is in release mode, it will still be printed in the terminal.
debugPrint generally is used to avoid the printing limit of each OS, if default debugPrintThrottled callback is used. It will also print in production, but you can customize it to work only in dev mode:
void main() {
if (kReleaseMode) {
debugPrint = (String? message, {int? wrapWidth}) {};
}
}
With this when the debugPrint statements in your code called in production, it won’t be printed to the console since you gave this function an empty callback.
was just wondering if I can determine if my app currently runs in a Testing environment.
Reason is that I am running automated screenshots and want to hide/modify parts of my App only when running that UI Test.
For example I'd like to skip registering for push notifications to avoid that iOS Popup at launch.
I'm searching for something like
if (kTestingMode) { ... }
I know that we do have a driver that basically launches the app and then connects. Guess the App actually does not even know if it is running in Testmode or not. But maybe someone knows an answer.
Thanks!
Some answers aim to detect if you are in debug mode. The question was about how to detect if you are in a test environment, not if you are in debug mode. In fact, when you run a test, you are in debug mode, but you can run an app in debug mode even without running a test.
In order to properly detect if you are running a test, you can check for the presence of the key FLUTTER_TEST in Platform.environment.
import 'dart:io' show Platform;
if (Platform.environment.containsKey('FLUTTER_TEST')) { ... }
Another solutions is to use --dart-define build environment variable. It is available from Flutter 1.17
Example of running tests with --dart-define:
flutter drive --dart-define=testing_mode=true --target=test_driver/main.dart
In code you can check this environment variable with the following code:
const bool.fromEnvironment('testing_mode', defaultValue: false)
Not using const can lead to the variable not being read on mobile, see here.
Okay I just found a solution my myself.
What I did is introduce a global variable which I will set in my main driver.
First I created a new globals.dart file:
library my_prj.globals;
bool testingActive = false;
Then, in my test_driver/main.dart file I import that and set the testingActive variable to true
import '../lib/globals.dart' as globals;
..
void main() {
final DataHandler handler = (_) async {
final response = {};
return Future.value(c.jsonEncode(response));
};
// Enable integration testing with the Flutter Driver extension.
// See https://flutter.io/testing/ for more info.
enableFlutterDriverExtension(handler: handler);
globals.testingActive = true;
WidgetsApp.debugAllowBannerOverride = false; // remove debug banner
runApp(App());
}
Now, I do have this global variable everywhere in my Flutter App by simply importing and checking.
e.g. in my app.dart
import '../globals.dart' as globals;
...
if (globals.testingActive) {
print("We are in a testing environment!");
}
Is there a better solution? Guess this works just fine!
I have another solution for this, may be this would work out as well for you. Let me know if that goes well with you or not.
1. So, I am suggesting to use assert(), as it only runs on debug mode.
Here is an example for navigator:
assert(() {
if (navigator == null && !nullOk) {
throw new FlutterError(
'Error!!!'
);
}
return true;
}());
Note: In particular the () at the end of the call - assert can only operate on a boolean, so just passing in a function doesn't work.
2. Other way is to use kReleaseMode from package package:flutter/foundation.dart
kReleaseMode is a constant. Therefore the compiler is correctly able to remove unused code, and we can safely do:
import 'package:flutter/foundation.dart' as Foundation;
//is release mode
if (Foundation.kReleaseMode) {
print('release mode');
} else {
print('debug mode');
}
3. This is the snippet which will be helpful for you:
bool get isInDebugMode {
bool inDebugMode = false;
assert(inDebugMode = true);
return inDebugMode;
}
If not you can configure your IDE to launch a different main.dart in debug mode where you can set a boolean.
I'm trying to use Casablanca to consume a REST api.
I've been following the microsoft tutorial, how ever i'm getting a crash and I cannot figure it out.
I'm using visual studio 2017 with C++11
I've codded a function GetRequest() that do work when used in a new empty project, but when I try to use it on my Project (Very big project with millions of code lines).
I'm crashing in the constructor of http_client, in the file xmemory0 line 118.
const uintptr_t _Ptr_container = _Ptr_user[-1];
This is a link to the callstack : https://i.imgur.com/lBm0Hv7.png
void RestManager::GetRequest()
{
auto fileStream = std::make_shared<ostream>();
// Open stream to output file.
pplx::task<void> requestTask = fstream::open_ostream(U("results.html")).then([=](ostream outFile)
{
*fileStream = outFile;
// Create http_client to send the request.
http_client client(U("XXX/XXX.svc/"));
// Build request URI and start the request.
uri_builder builder(U("/IsLive"));
builder.append_query(U("q"), U("cpprestsdk github"));
return client.request(methods::GET, builder.to_string());
})
// Handle response headers arriving.
.then([=](http_response response)
{
printf("Received response status code:%u\n", response.status_code());
// Write response body into the file.
return response.body().read_to_end(fileStream->streambuf());
})
// Close the file stream.
.then([=](size_t)
{
return fileStream->close();
});
// Wait for all the outstanding I/O to complete and handle any exceptions
try
{
requestTask.wait();
}
catch (const std::exception &e)
{
printf("Error exception:%s\n", e.what());
}
}
EDIT : I just want to add that the http_client constructor is the issue. It always crash inside it no matter what I send as parameter.
The wierd thing is that it's not crashing when i just make a main() that call this function.
I guess it must be due to some memory issues, however I have no idea how could I debug that.
Does anyone would have an idea about it?
Thanks and have a great day!
I've experienced a similar issue on ubuntu. It works in an empty project, but crashes randomly when put into an existing large project, complaining memory corruptions.
Turns out that the existing project loaded a proprietary library, which is using cpprestsdk (casablanca) internally. Even cpprestsdk is static linked, its symbols are still exported as Weak Symbols. So either my code crashes, or the proprietary library crashes.
Ideally, my project can be divided into several libraries, and load them with RTLD_LOCAL to avoid symbol clashes. But the proprietary library in my project only accept RTLD_GLOBAL, otherwise it crashes... So the import order and flags become important:
dlopen("my-lib-uses-cpprest", RTLD_LOCAL); //To avoid polluting the global
dlopen("proprietary-lib-with-built-in-cpprest", RTLD_GLOBAL); //In my case, this lib must be global
dlopen("another-lib-uses-cpprest", RTLD_DEEPBIND); //To avoid being affected by global
"it will probably never concern anyone."
I agree with that.
I guess this issues was very specific, and it will probably never concern anyone, but still I'm going to update on everything I found out about it.
On this project, we are using custom allocator, if i'm not wrong, it's not possible to give our custom allocator to this lib, which result to many random crash.
A good option to fix it would be to use the static version to this lib, however, since we are using a lot of dynamic lib, this option wasn't possible for us.
If you are on my case, I would advice to use the libcurl and rapidjson, it's a bit harder to use, but you can achieve the same goal.
I've run into the dreaded Reflection.emit issue in my webplayer build and am unable to locate what is triggering it. I'm currently commenting out code method by method and rebuilding to locate the cause and have narrowed it down to the below.
I'm not using JSON so the various JSON libraries aren't the cause, nor any of the other result suggestions returned by google.
How can i more easily go about locating the cause of this error. I have full stack trace on and well as full debugging, but all i get is the following console output.
NotSupportedException: C:\Program Files\Unity 2018.2.0b2\Editor\Data\il2cpp\libil2cpp\icalls\mscorlib\System.Reflection.Emit\AssemblyBuilder.cpp(20) : Unsupported internal call for IL2CPP:AssemblyBuilder::basic_init - System.Reflection.Emit is not supported.
Rethrow as TypeInitializationException: The type initializer for 'System.Reflection.Emit.DynamicMethod.AnonHostModuleHolder' threw an exception.
//NOTE: appM.procM is a C# .Net 4.x dynamic variable EG:
//public dynamic procM = GetProcClass(strProcName)
public void ShowProcList() {
/* Rest of method commented out*/
if(appM.procM == null){
procList.Initialize(appM.procM.lstNames, this);
}
/* Rest of method commented out*/
}
public void Initialize(List<string> lstNames, UIM um, string currProc=null) {
uiM = um;
//cleanup of the list before populating
foreach(Transform fld in Panel.transform) {
Destroy(fld.gameObject);
}
/* Rest of method commented out*/
}
Update: I narrowed down the problem line of code, but haven't closed the question as there's got to be an easier way than commenting out line by line and rebuilding.
For future searchers, the issue is the if(appM.procM == null) check. As procM is a dynamic variable reflection is used which kills AOT in webGL builds. No compiler warnings were generated to save myself from myself.
Nevermind, i am an idiot, The option Enable Exceptions under Player Settings was set to Full Without Stacktrace and not Full with Stacktrace.
The value Full With Stacktrace contains the pertinent data. Easily locatable in the browsers console. Warning that full debugging does increase build times and slow down the application.