Logging in Concrete CMS
August 7, 2025 · AI Conversations
we are using concrete cms 9
Here’s how you can log messages from your package:
—
### ✅ Step-by-Step: Logging in Concrete CMS 9 from a Custom Package
#### 1. **Import the Logger Facade**
At the top of your PHP file (e.g., in a controller, service, or class), import the Logger:
use ConcreteCoreLoggingLoggerFactory;
use PsrLogLoggerInterface;
#### 2. **Get the Logger Instance**
You can get the logger via the application's service container:
$logger = app(LoggerFactory::class)->createLogger('shopping_feed'); // Use a custom channel name
> This `shopping_feed` channel will still write to the same `Logs` section in the dashboard (`/dashboard/reports/logs`), and you can filter by channel name.
#### 3. **Write Log Messages**
Now use standard PSR-3 log levels:
$logger->info('Feed generated successfully for ID: ' . $feedId);
$logger->warning('Feed generation took longer than expected.');
$logger->error('Failed to generate feed: ' . $exception->getMessage());
—
### 🔧 Example: Logging from a Custom Controller
use ConcreteCoreLoggingLoggerFactory;
class FeedGenerator
{
protected $logger;
public function __construct(LoggerFactory $loggerFactory)
{
$this->logger = $loggerFactory->createLogger('shopping_feed');
}
public function generate($feedId)
{
try {
// your feed generation logic...
$this->logger->info("Feed generated for ID: {$feedId}");
} catch (Exception $e) {
$this->logger->error("Feed generation failed: " . $e->getMessage());
}
}
}
If you're in a controller or class where dependency injection isn’t feasible, you can also call it directly using:
$logger = Core::make(LoggerFactory::class)->createLogger('shopping_feed');
$logger->debug('This is a debug message');
—
### 📍Where It Appears in Concrete CMS Admin
You’ll find your logs in:
Dashboard → Reports → Logs
Filter by **Channel** to see only logs from `shopping_feed`.
—
Would you like me to include this in your package’s installation routine or inject it via a service provider?
use for this
—
### ✅ Update your `logFeedStatus()` method
Here’s how you can implement it:
use ConcreteCoreLoggingLoggerFactory;
protected function logFeedStatus($db, $feedId, $level = 'info', $message = '')
{
// Optional: you can also insert into a custom table here using $db if needed
// Get Concrete CMS logger for 'shopping_feed' channel
$logger = app(LoggerFactory::class)->createLogger('shopping_feed');
// Prepare the full message
$fullMessage = "Feed ID: {$feedId} — {$message}";
// Log using dynamic level
switch (strtolower($level)) {
case 'debug':
$logger->debug($fullMessage);
break;
case 'notice':
$logger->notice($fullMessage);
break;
case 'warning':
$logger->warning($fullMessage);
break;
case 'error':
$logger->error($fullMessage);
break;
case 'critical':
$logger->critical($fullMessage);
break;
case 'alert':
$logger->alert($fullMessage);
break;
case 'emergency':
$logger->emergency($fullMessage);
break;
case 'info':
default:
$logger->info($fullMessage);
break;
}
}
—
### 📌 Usage Example
$this->logFeedStatus($db, $config['id'], 'error', 'No matching product found');
This will log the message:
> `Feed ID: 12 — No matching product found`
…to the **Concrete CMS Logs dashboard** under channel `shopping_feed`.
—
Let me know if you'd like this extended to store in a custom DB table *and* write to Concrete logs simultaneously.
{
try {
$now = (new DateTime())->format('Y-m-d H:i:s');
$db->insert('shoppingfeedlog', [
'feed_id' => $feedId,
'updated_at' => $now,
'status' => $status,
'error_message' => $message
]);
} catch (Exception $logException) {
// Optional: Log error to file or skip silently
// error_log("Feed log error: " . $logException->getMessage());
}
}
replace this
1. **Inserts into your custom `shoppingfeedlog` table** (as it currently does).
2. **Also logs to Concrete CMS’s built-in Logs dashboard** using `LoggerFactory`.
—
### ✅ Updated `logFeedStatus()` with Concrete CMS Logging
use ConcreteCoreLoggingLoggerFactory;
use DateTime;
use Exception;
protected function logFeedStatus($db, $feedId, $status, $message = null)
{
try {
$now = (new DateTime())->format('Y-m-d H:i:s');
// Save to custom table
$db->insert('shoppingfeedlog', [
'feed_id' => $feedId,
'updated_at' => $now,
'status' => $status,
'error_message' => $message
]);
// Also log to Concrete CMS core logger
$logger = app(LoggerFactory::class)->createLogger('shopping_feed');
$logMessage = "Feed ID: {$feedId} — Status: {$status}" . ($message ? " — {$message}" : '');
switch (strtolower($status)) {
case 'debug':
$logger->debug($logMessage);
break;
case 'notice':
$logger->notice($logMessage);
break;
case 'warning':
$logger->warning($logMessage);
break;
case 'error':
$logger->error($logMessage);
break;
case 'critical':
$logger->critical($logMessage);
break;
case 'alert':
$logger->alert($logMessage);
break;
case 'emergency':
$logger->emergency($logMessage);
break;
case 'info':
default:
$logger->info($logMessage);
break;
}
} catch (Exception $logException) {
// Avoid infinite logging loops – log to PHP error log
error_log("Feed logging failed: " . $logException->getMessage());
}
}
—
### 📝 Notes
– The `status` field is reused as the log level (e.g., `'info'`, `'error'`, `'warning'`).
– If you store custom statuses (like `'completed'` or `'processing'`), you can normalize them or default to `'info'`.
Let me know if you want a fallback/default level or to sanitize unknown statuses.