55namespace Stancl \Tenancy \Bootstrappers ;
66
77use Closure ;
8- use Illuminate \Contracts \Config \Repository as Config ;
8+ use Illuminate \Contracts \Config \Repository ;
99use Illuminate \Database \Eloquent \Model ;
1010use Illuminate \Log \LogManager ;
11- use Illuminate \Support \Arr ;
1211use Illuminate \Support \Str ;
1312use InvalidArgumentException ;
1413use Stancl \Tenancy \Contracts \TenancyBootstrapper ;
2221 *
2322 * For this to work correctly:
2423 * - this bootstrapper must run *after* FilesystemTenancyBootstrapper,
25- * since FilesystemTenancyBootstrapper makes storage_path() return the tenant-specific storage path
24+ * since FilesystemTenancyBootstrapper adjusts storage_path() for the tenant
2625 * - storage path suffixing has to be enabled (= config('tenancy.filesystem.suffix_storage_path')
27- * has to be true), since the storage path suffix is what separates logs by tenant
26+ * must be true), since the storage path suffix is what separates filesystem-based logs
2827 *
29- * Also supports custom channel overrides ( see the $channelOverrides property) .
28+ * For logging channels that are not filesystem-based, see the $channelOverrides logic .
3029 *
3130 * @see Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper
3231 */
@@ -56,14 +55,15 @@ class LogTenancyBootstrapper implements TenancyBootstrapper
5655 * Custom channel configuration overrides.
5756 *
5857 * All channels included here will be configured using the provided override.
59- * The overrides take precedence over the default ($storagePathChannels) behavior.
58+ * The overrides take precedence over the $storagePathChannels behavior
59+ * when both approaches are used for the same channel.
6060 *
6161 * You can either map tenant attributes to channel config keys using an array,
6262 * or provide a closure that returns the full channel config array.
6363 *
6464 * Examples:
65- * - Array mapping (the default approach) : ['slack' => ['url' => 'webhookUrl']]
66- * - this maps $tenant->webhookUrl to slack.url (if $tenant->webhookUrl is not null, otherwise, the override is ignored)
65+ * - Array mapping: ['slack' => ['url' => 'webhookUrl']]
66+ * - this maps $tenant->webhookUrl to slack.url (if $tenant->webhookUrl is not null; otherwise the override is ignored)
6767 * - Closure: ['slack' => fn (Tenant $tenant, array $channel) => array_merge($channel, ['url' => $tenant->slackUrl])]
6868 * - this merges ['url' => $tenant->slackUrl] into the channel's config.
6969 *
@@ -72,7 +72,7 @@ class LogTenancyBootstrapper implements TenancyBootstrapper
7272 public static array $ channelOverrides = [];
7373
7474 public function __construct (
75- protected Config $ config ,
75+ protected Repository $ config ,
7676 protected LogManager $ logManager ,
7777 ) {}
7878
@@ -86,11 +86,11 @@ public function bootstrap(Tenant $tenant): void
8686 $ this ->forgetChannels ($ this ->configuredChannels );
8787 } catch (\Throwable $ exception ) {
8888 // If an exception is thrown while updating the logging config, the logging config
89- // could be left in a corrupt (tenant) state, so we revert to the original config
90- // to e.g. avoid logging the failure in the tenant log (which would happen if
91- // the channel wasn't resolved before).
89+ // could be left in a corrupt state, so we revert to the original config to
90+ // to avoid logging the exception in a tenant channel or a broken channel.
9291 $ this ->revert ();
9392
93+ // We re-throw the exception after having reverted the logging config to central.
9494 throw $ exception ;
9595 }
9696 }
@@ -116,7 +116,7 @@ protected function getChannels(): array
116116 /**
117117 * Include the default channel in the list of channels to configure/re-resolve.
118118 *
119- * Including the default channel is harmless (if it's not overridden or not in $storagePathChannels,
119+ * Including the default channel is harmless (if it's not overridden and not in $storagePathChannels,
120120 * it'll just be forgotten and re-resolved on the next use with the original config), and for the
121121 * case where 'stack' is the default, this is necessary since the 'stack' channel will be resolved
122122 * and saved in the log manager, and its stale config could accidentally be used instead of the stack member channels.
@@ -150,15 +150,14 @@ protected function configureChannels(array $channels, Tenant $tenant): void
150150 if (isset (static ::$ channelOverrides [$ channel ])) {
151151 $ this ->overrideChannelConfig ($ channel , static ::$ channelOverrides [$ channel ], $ tenant );
152152 } elseif (in_array ($ channel , static ::$ storagePathChannels )) {
153- // Set storage path channels to use tenant-specific directory (default behavior).
154- // The tenant log will be located at e.g. "storage/tenant{$tenantKey}/logs/laravel.log",
155- // assuming FilesystemTenancyBootstrapper is used before this bootstrapper.
153+ // Set storage path channels to use a tenant-specific directory (default behavior).
154+ // The tenant log will be located at e.g. "storage/tenant{$tenantKey}/logs/laravel.log".
156155 $ originalChannelPath = $ this ->config ->get ("logging.channels. {$ channel }.path " );
157156 $ centralStoragePath = Str::before (storage_path (), $ this ->config ->get ('tenancy.filesystem.suffix_base ' ) . $ tenant ->getTenantKey ());
158157
159158 // The tenant log will inherit the segment that follows the storage path from the central channel path config.
160- // For example, if a channel's path is configured to storage_path('custom/ logs/path .log') (storage/custom/ logs/path .log),
161- // the 'custom/ logs/path .log' segment will be passed to storage_path() in the tenant context (storage/tenantfoo/custom/ logs/path .log).
159+ // For example, if a channel's path is configured to storage_path('logs/foo .log') (storage/logs/foo .log),
160+ // the 'logs/foo .log' segment will be passed to storage_path() in the tenant context (storage/tenant123/ logs/foo .log).
162161 $ this ->config ->set ("logging.channels. {$ channel }.path " , storage_path (Str::after ($ originalChannelPath , $ centralStoragePath )));
163162 }
164163 }
@@ -172,7 +171,8 @@ protected function overrideChannelConfig(string $channel, array|Closure $overrid
172171 // the override is ignored and the channel config key's value remains unchanged.
173172 foreach ($ override as $ configKey => $ tenantAttributeName ) {
174173 /** @var Tenant&Model $tenant */
175- $ tenantAttribute = Arr::get ($ tenant , $ tenantAttributeName );
174+
175+ $ tenantAttribute = $ tenant ->getAttribute ($ tenantAttributeName );
176176
177177 if ($ tenantAttribute !== null ) {
178178 $ this ->config ->set ("logging.channels. {$ channel }. {$ configKey }" , $ tenantAttribute );
0 commit comments