Make a scheduled job out of it!
public class TruncateLog implements Database.AllowsCallouts, Schedulable, Queueable {
Integer currentUsage;
public void execute(SchedulableContext context) {
AggregateResult[] results = [SELECT SUM(LogLength) sum FROM ApexLog];
// Adjust to your liking. I set to 750,000,000/1,000,000,000 allowed.
if(results.isEmpty() || ((Integer)results[0].get('sum')<750000000)) {
return;
}
currentUsage = (Integer)results[0].get('sum');
System.enqueueJob(this);
}
public void execute(QueueableContext context) {
Url baseUrl = Url.getSalesforceBaseUrl();
String baseEndpoint = '/services/data/v55.0/composite/sobjects?ids=';
List<String[]> batches = new List<String[]>();
{
String[] batch = new String[0];
Integer accumulatedLogSize = 0;
for(ApexLog log: [SELECT LogLength FROM ApexLog ORDER BY LastModifiedDate ASC LIMIT 20000]) {
accumulatedLogSize += log.LogLength;
batch.add(log.Id);
// Reduces by 500,000,000. Adjust to your liking.
if(accumulatedLogSize > 500000000) {
break;
}
// Can only do 200 at a time unless we want do to JSON stuff. I do not.
if(batch.size() == 200) {
batches.add(batch);
batch = new String[0];
}
}
if(batch.size() > 0) {
batches.add(batch);
}
}
for(String[] batch: batches) {
HttpRequest req = new HttpRequest();
req.setHeader('Authorization', 'OAuth '+UserInfo.getSessionId());
req.setMethod('DELETE');
req.setEndpoint(new Url(baseUrl, baseEndpoint+String.join(batch,'&')).toExternalForm());
try {
new Http().send(req);
} catch(Exception e) {
// It didn't like that batch for some reason. We'll try to get it next time
}
}
}
}
Schedule this to run hourly:
System.schedule('TruncateLogsHourly', '0 0 * * * ?', new TruncateLog());
Now, assuming your users haven't hit the maximum of 1GB in an hour, they'll magically have at least 500,000,000 bytes of log data removed.