Disable Log::info in production using Laravel - php

I assumed that by default the Log::info calls wouldn't log in production, but they are still coming in.
Im setting production using my .env file
APP_ENV=production
APP_DEBUG=false
Ive tried these commands as well, but no luck
composer dump-autoload
php artisan cache:clear
php artisan optimize
Am i missing something?

For anyone still finding this thread (8 years later):
Configure your log channels in config/logging.php file
Set "level" parameter for your log channel to a .env variable
Example:
'channels' => [
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => 'Lumen Log',
'emoji' => ':boom:',
'level' => env('LOG_LEVEL', 'error'),
]
]
Now you can set the LOG_LEVEL variable in your .env file for each environment

Well, I think that it's too late to search for all the Log::info() and do the proposed answer by #jon__o
if (App::environment('local', 'staging')) {
Log::info($error);
}
But you can still do something. You can override the default Laravel logger instance with your own implementation.
Go to your ApplicationServiceProvider and override the log instance with a custom one:
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->registerLogger();
}
/**
* Register the logger instance in the container.
*
* #return MyCustomWriter
*/
protected function registerLogger()
{
$this->app->instance('log', $log = new MyCustomWriter(
new Monolog($this->app->environment()), $app['events'])
);
$log->dontLogInfoOnEnvironmnets(['production', 'staging', 'other']);
return $log;
}
Now you can create your custom writer by just extending the Laravel's Writer and overriding the info() method.
class MyCustomWriter extends \Illuminate\Log\Writer
{
protected $dontInfoOn = [];
/**
* Log an informational message to the logs.
*
* #param string $message
* #param array $context
* #return void
*/
public function info($message, array $context = [])
{
// Since we are providing the app environment to the Monolog instance in out ApplicationServiceProvider
// we can get the environment from the Monolog getName() method
if(!in_array($this->monolog->getName(), $this->dontInfoOn)) {
return parent::info($message, $context);
}
}
/**
* Don't log info() on the supplied environments .
*
* #param array $environments
* #return void
*/
public function dontLogInfoOnEnvironmnets(array $environments)
{
$this->dontInfoOn = $environments;
}
}
This way, you can still keep you Log::info on testing environments without checking every time.

Only the displaying of errors will be suppressed when your application is not in debug mode. The Log::info() function will always log when called.
The simple solution is for you to wrap that Log::info() function in something like this:
if (App::environment('local', 'staging')) {
Log::info($error);
}
Be sure to include the App facade use App; at the top of your file. Alternatively you can use the app() helper to get the environment: $environment = app()->environment();.

Related

Using TypoScriptFrontendController features in AuthenticationService? / Save Data to User in Authenticator?

So I use a Service Class (extends from TYPO3\CMS\Core\Authentication\AuthenticationService) to authenticate our Frontend Users using OAuth2. These Services are automatically instantiated and called via Typos own Middleware: FrontendUserAuthenticator.
In this class I used to save data from the authentication result to $GLOBALS['TSFE']->fe_user using setKey('ses', 'key', 'data'), which seems is not possible anymore since v10. How would I go about still doing this?
The documentation is sparse
https://docs.typo3.org/c/typo3/cms-core/master/en-us/Changelog/9.4/Deprecation-85878-EidUtilityAndVariousTSFEMethods.html
https://docs.typo3.org/m/typo3/reference-coreapi/10.4/en-us/ApiOverview/Context/Index.html
I've tried the following:
constructor injecting the TSFE using DI
class FrontendOAuthService extends AuthenticationService
{
public function __construct(TypoScriptFrontendController $TSFE) {
=> LogicException: TypoScriptFrontendController was tried to be injected before initial creation
changing the Middlewares order to have it instantiate before the Auth Middleware
(packages/extension_name/Configuration/RequestMiddlewares.php)
return [
'frontend' => [
'typo3/cms-frontend/tsfe' => [
'disabled' => true,
],
'vendor/extension_name/frontend-oauth' => [
'target' => \TYPO3\CMS\Frontend\Middleware\TypoScriptFrontendInitialization::class,
'before' => [
'typo3/cms-frontend/authentication',
],
'after' => [
'typo3/cms-frontend/eid',
'typo3/cms-frontend/page-argument-validator',
],
],
],
];
=> UnexpectedValueException: Your dependencies have cycles. That will not work out.
instantiating the TSFE myself
/** #var ObjectManager $objectManager */
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
/** #var DealerService $dealerService */
$lang = $site->getDefaultLanguage();
$siteLanguage = $objectManager->get(SiteLanguage::class, $lang->getLanguageId(), $lang->getLocale(), $lang->getBase(), []);
/** #var TypoScriptFrontendController $TSFE */
$TSFE = $objectManager->get(
TypoScriptFrontendController::class,
GeneralUtility::makeInstance(Context::class),
$site,
$siteLanguage,
GeneralUtility::_GP('no_cache'),
GeneralUtility::_GP('cHash')
);
=> the $TSFE->fe_user is an emptystring ("")
using the UserAspect
/** #var Context $context */
$context = GeneralUtility::makeInstance(Context::class);
$feUser = $context->getAspect('frontend.user');
$feUser->set...
=> Aspects are read-only
adding vars to the user data in the getUser method of the AuthenticationService
(packages/extension_name/Classes/Service/FrontendOAuthService.php)
public function getUser()
{
$user = allBusinessCodeHere();
$user['my_own_key'] = 'myData';
return $user;
=> is not propagated to the UserAspect(frontend.user) nor the $TSFE->fe_user
I'm out of ideas guys.
I had a similar problem when i wanted to use redirects with record links.
I ended up disabling the original redirect middleware and adding my own with a mocked version of tsfe.
The extension can be found here:
https://github.com/BenjaminBeck/bdm_middleware_redirect_with_tsfe
Late to the party, but I had the same issue and was able to solve it:
https://docs.typo3.org/c/typo3/cms-core/master/en-us/Changelog/10.0/Breaking-88540-ChangedRequestWorkflowForFrontendRequests.html states:
Storing session data from a Frontend User Session / Anonymous session
is now triggered within the Frontend User
(frontend-user-authenticator) Middleware, at a later point - once the
page was generated. Up until TYPO3 v9, this was part of the
RequestHandler logic right after content was put together. This was
due to legacy reasons of the previous hook execution order. Migration
Consider using a PSR-15 middleware instead of using a hook, or
explicitly call storeSessionData() within the PHP hook if necessary.
In my MyAuthenticationService extends AbstractAuthenticationService in method getUser() I set $_SESSION['myvendor/myextension/accessToken'] to the token received by the external oauth service. In my SaveSessionMiddleware I save this token to the FrontendUserAuthentication object using setKey() which by then is available:
EXT:myextension/Configuration/RequestMiddlewares.php
return [
'frontend' => [
'myvendor/myextension/save-session-middleware' => [
'target' => \MyVendor\MyExtension\Middleware\SaveSessionMiddleware::class,
'after' => [
'typo3/cms-frontend/authentication',
],
]
]
];
EXT:myextension/Classes/Middleware/SaveSessionMiddleware.php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
class SaveSessionMiddleware implements MiddlewareInterface {
/**
* #param ServerRequestInterface $request
* #param RequestHandlerInterface $handler
* #return ResponseInterface
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
if (!empty($_SESSION['myvendor/myextension/accessToken'])) {
$this->getFrontendUserAuthentication()->setKey(
'ses',
'myvendor/myextension/accessToken',
$_SESSION['myvendor/myextension/accessToken']);
unset($_SESSION['myvendor/myextension/accessToken']);
}
return $handler->handle($request);
}
private function getFrontendUserAuthentication(): FrontendUserAuthentication {
return $GLOBALS['TSFE']->fe_user;
}
}

Laravel MonoLog, pushProcessor not Logging Addition attributes

I want to be able to add a unique id (Uid) to my logging.
In Example 1: Which is depended on config/logging.php and ProcessorTap files below is not working as expected. The logging is configured to use stdout which refers to the ProcessorTap class that is suppose to add a Uid, when the log statement is created (in accordance with UidProcessor)
Example 2: Which uses purely Mono classes works as expected.
Why isnt Example 1 adding the Uid to the logs, when laravel ("laravel/framework": "5.7.*") should be using Monolog classes as well ?
Example 1: When this api is invoked, the output for Log::info('test') does not include UiD
Route::get('/test', function () {
Log::info('test'); //output = [2020-03-24 04:51:16] local.INFO: test
});
config/logging.php:
'default' => env('LOG_CHANNEL', 'stdout'), //.env LOG_CHANNEL=stdout
'stdout' => [
'driver' => 'monolog',
'handler' => StreamHandler::class,
'with' => [
'stream' => 'php://stdout',
],
'tap' => [
ProcessorTap::class,
],
]
ProcessorTap:
use Monolog\Processor\UidProcessor;
class ProcessorTap
{
/**
* Customize the given logger instance.
*
* #param \Illuminate\Log\Logger $logger
* #return void
*/
public function __invoke($logger)
{
$logger->pushProcessor(new UidProcessor());
}
}
Example 2: Working correctly the Uid (a484a6729e14996c0af1)
is added to the log for $logger->info('test')
use Monolog\Logger;
use Monolog\Processor\UidProcessor;
Route::get('/test', function () {
$logger = new Logger('main');
$logger->pushProcessor(new UidProcessor(20));
$logger->info('test'); // output = [2020-03-24 04:57:26] main.INFO: test [] {"uid":"a484a6729e14996c0af1"}
});
This might be a laravel (5.7)/mono version specific issue, but I was able to resolve the via iterating via the handlers and calling pushProcessor
use Monolog\Processor\UidProcessor;
class ProcessorTap
{
/**
* Customize the given logger instance.
*
* #param \Illuminate\Log\Logger $logger
* #return void
*/
public function __invoke($logger)
{
collect($logger->getHandlers())->each(function ($handler) {
$handler->pushProcessor(new UidProcessor());
});
}
}

Laravel logging.channels.single.path with queue is cached?

Im using Queue::before in AppServiceProvider.php and set logging.channels.single.path value every time when job started:
config(['logging.channels.single.path' => storage_path('logs/accounts/'.$command->acc->login.'.log')]);
When I running 1 job all ok - logs in the right place.
When running 2 or more it writing logs to different files - one account can write to another accounts logfile. Why is it happening? It looks like it is caching the config variable.
Queue on horizon redis. One job after done dispatching another same job with the same $acc instance.
Queue::before(function (JobProcessing $event) {
$job = $event->job->payload();
$command = unserialize($job['data']['command']);
Added ^^^ from where $command going.
Customization is now done through invoking a custom formatter for Monolog.
This can be setup in config/logging.php, note the non-default tap parameter:
'channels' => [
'daily' => [
'driver' => 'daily',
'tap' => [App\Logging\CustomFilenames::class],
'path' => storage_path('logs/accounts/laravel.log'),
'level' => 'debug',
],
]
In your custom formatter, you can manipulate the Monolog logger however you wish:
<?php
namespace App\Logging;
use Monolog\Handler\RotatingFileHandler;
class CustomFilenames
{
/**
* Customize the given logger instance.
*
* #param \Illuminate\Log\Logger $logger
* #return void
*/
public function __invoke($logger) {
foreach ($logger->getHandlers() as $handler) {
if ($handler instanceof RotatingFileHandler) {
$login = $command->acc->login;
$handler->setFilenameFormat("{filename}-$login-{date}", 'Y-m-d');
}
}
}
}
See: https://laravel.com/docs/5.6/logging#advanced-monolog-channel-customization
https://github.com/Seldaek/monolog/blob/master/src/Monolog/Handler/RotatingFileHandler.php
The configuration values work globaly for all sessions, like global variables (
See the exampe here https://laravel.io/forum/how-can-i-set-global-dynamic-variables-in-laravel)
You set the value in the config file always to the last login. Therefore all new logs go in the new named config file.

Laravel Trait not found PHP Fatal Error

I am working on a project which has Laravel 5.3 version and using Laravel Infyom Generator, somehow it generated all these traits and other test files such as (ApiTest, RepositoryTest, ...etc). when I try to run PHPUNIT I am getting this error Can someone help me to find out why I am getting this error?
PHP Fatal error: Trait 'MakeCustomerTrait' not found in C:\Users\ahmed\dev\gamla\tests\CustomerApiTest.php on line 8
Fatal error: Trait 'MakeCustomerTrait' not found in C:\Users\ahmed\dev\gamla\tests\CustomerApiTest.php on line 8
I want to start making new tests for my project do I need to delete these files? because it keeps giving me that error?
screenshot of CustomerApiTest code:
MakeCustomerTrait
<?php
use Faker\Factory as Faker;
use App\Models\Customer;
use App\Repositories\CustomerRepository;
trait MakeCustomerTrait
{
/**
* Create fake instance of Customer and save it in database
*
* #param array $customerFields
* #return Customer
*/
public function makeCustomer($customerFields = [])
{
/** #var CustomerRepository $customerRepo */
$customerRepo = App::make(CustomerRepository::class);
$theme = $this->fakeCustomerData($customerFields);
return $customerRepo->create($theme);
}
/**
* Get fake instance of Customer
*
* #param array $customerFields
* #return Customer
*/
public function fakeCustomer($customerFields = [])
{
return new Customer($this->fakeCustomerData($customerFields));
}
/**
* Get fake data of Customer
*
* #param array $postFields
* #return array
*/
public function fakeCustomerData($customerFields = [])
{
$fake = Faker::create();
return array_merge([
'name' => $fake->word,
'address_street' => $fake->word,
'address_zip' => $fake->word,
'address_city' => $fake->word,
'address_country' => $fake->word,
'shipping_address_street' => $fake->word,
'shipping_address_zip' => $fake->word,
'shipping_address_city' => $fake->word,
'shipping_address_country' => $fake->word,
'contact_person_id' => $fake->randomDigitNotNull,
'created_at' => $fake->word,
'updated_at' => $fake->word
], $customerFields);
}
}
Actually what is happening is here is autoloader is unable to resolve the class in your code. Laravel uses PSR-4 standards to autoload classes which needs fully qualified name spaces for the class which also represents the path of the file which holds the class.
See it this way that if you want to load a class inside your Laravel app directory at the following address :
app/repositories/users/UserRoleRepository.php
You will specify the namespace of your class like App\repositories\users with class name UserRoleRepository so the autoloader can load your class. Otherwise you have to include the file of your class manually.
You can register custom autoloads in your composer.json and by running the following command composer dump-autoload.
You can find more about it over internet like this
Hope it would help.

Customize Laravel error reporting to remove stack trace

How can you turn off or remove the stack traces from Laravel's error reports. They're annoying if you want to read them in your console. I know you can add a custom handler in app/Exceptions/Handler.php, but I have no idea how to do that.
Setting APP_DEBUG=false in your .env file works fine for the frontend.
If you don't want the stack trace lines to be outputted in the log files only, try this.
In /app/Exceptions/Handler.php add use Log; at the top, then add this in the report function:
Log::error('['.$e->getCode().'] "'.$e->getMessage().'" on line '.$e->getTrace()[0]['line'].' of file '.$e->getTrace()[0]['file']);
And remove:
parent::report($e);
More info: https://laracasts.com/discuss/channels/laravel/remove-stacktrace-from-log-files
Since I can not comment on or edit #Harold answer, here is a improved sollution:
In /app/Exceptions/Handler.php add use Log; at the top,
Then modify the report function:
public function report(Exception $e)
{
if (!config('app.debug')) {
Log::error('['.$e->getCode().'] "'.$e->getMessage().'" on line '.$e->getTrace()[0]['line'].' of file '.$e->getTrace()[0]['file']);
} else {
parent::report($e);
}
}
For those who don't like "add this, remove that" kind of instructions, here's what app/Exceptions/Handler.php should look like, based on Laravel 5.7, and sticking to a message format like PHP's native one:
<?php
namespace App\Exceptions;
use Log;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Auth\AuthenticationException;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* #var array
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* #var array
*/
protected $dontFlash = [
'password',
'password_confirmation',
];
/**
* Report or log an exception.
*
* #param \Exception $exception
* #return void
*/
public function report(Exception $exception)
{
Log::error(sprintf(
"Uncaught exception '%s' with message '%s' in %s:%d",
get_class($exception),
$exception->getMessage(),
$exception->getTrace()[0]['file'],
$exception->getTrace()[0]['line']
));
// parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
return parent::render($request, $exception);
}
}
Note that you can replace Log::error() with a simple call to error_log() to write to PHP's standard error log. If you do that, you don't have to remove the call to parent::report(). That way you can keep the traces in the Laravel log for further debugging, but keep your main PHP log for quick checks.
Another way is to edit the log format in your logging config file. This means you don't have to override the default report function which would mean missing out on other logic within the parent function.
I set mine to this:
'daily' => [
'driver' => 'daily',
'formatter' =>LineFormatter::class,
'formatter_with' => [
'format' => "[%datetime%] %channel%.%level_name%: %message%\n %context%\n",
'dateFormat' => "Y-m-d H:i:s"
],
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'days' => 14,
],
simplely set your APP_DEBUG=false in your env file.
Harold and Jani's answers are correct.
However the log line is less detailed than the default one.
The best solution would be to edit the file:
vendor/laravel/frameworks/src/Illuminate/Log/LogManager.php
and add false argument when the includeStacktraces method is called.
add false to
$formatter->includeStacktraces();
so:
$formatter->includeStacktraces(false);
This will simply disable the stacktrace. Everything else remains the same.

Categories