-
Notifications
You must be signed in to change notification settings - Fork 564
Description
I've looked high and low and tried overriding the Google::Cloud::Vision module to inject debug info, but no matter what I do the app server crashes as soon as I try to instantiate a vision client with the line Google::Cloud::Vision.image_annotator
.
I am at a loss as to why this runs fine, connects to the cloud API and outputs as expected in a standalone script, but the same code fails with no exceptions, no logging, nothing but an abrupt server crash in a Rails controller.
For auth, I am using a straightforward service key in a .json file just to get a basic API call to analyze an image successfully.
I've also tried enabling GCV logging per the instructions at https://cloud.google.com/ruby/docs/reference/google-cloud-vision-v1/latest and that did nothing that I could see. If anyone has any suggestions or ideas to workaround or get at further ways to debug this, I'd love to hear them as I'm at a hard block on this now. What am I missing?
Environment details
- OS: Windows 10
- Ruby version: 3.3.3-p89
- Rails 7.1.3
- Puma 6.4.2
- gem 'google-cloud-vision'
Steps to reproduce
- Processing the route to DebugController#moderate (see below) crashes 100% of the time on
vision_client = Google::Cloud::Vision.image_annotator
.
Code examples
Standalone Ruby script (running this from console via "ruby debug_vision.rb" works and outputs two results as expected):
# debug_vision.rb
require "google/cloud/vision"
ENV["GOOGLE_APPLICATION_CREDENTIALS"] ||= ("D:/path_to/config/credentials/google_cloud_vision.json").to_s
Google::Cloud::Vision.configure do |config|
config.credentials = ENV["GOOGLE_APPLICATION_CREDENTIALS"]
puts "=== credentials: #{config.credentials}"
end
image_path = "D:/path_to/file.jpeg"
vision = Google::Cloud::Vision.image_annotator
puts "=== vision client initialized ==="
# Open the image file as an IO object
File.open(image_path, "rb") do |image_file|
response = vision.safe_search_detection image: image_file
safe_search = response.responses.first.safe_search_annotation
puts "Adult: #{safe_search.adult}"
puts "Violence: #{safe_search.violence}"
end
When running via Rails controller, the credentials are set via an initializer when the server starts:
# config/initializers/google_cloud_vision.rb
require "google/cloud/vision"
# Set the environment variable for Google Cloud credentials
ENV["GOOGLE_APPLICATION_CREDENTIALS"] ||= Rails.root.join("config/credentials/google_cloud_vision.json").to_s
Google::Cloud::Vision.configure do |config|
config.credentials = ENV["GOOGLE_APPLICATION_CREDENTIALS"]
end
Rails controller code (this method verifies credentials are correct and that a file is uploaded, but creating the image_annotator client object crashes the server):
# controllers/debug_controller.rb
class DebugController < ApplicationController
# Attempted all kinds of variations of including google/cloud/vision, no differences
# require "google/cloud/vision"
# include Google::Cloud::Vision
...
def moderate
Rails.logger.debug "========== DebugController#moderate..."
uploaded_file = params[:image]
unless uploaded_file.present?
flash[:alert] = "No file was uploaded!"
render :image
end
image_path = uploaded_file.tempfile.path
Rails.logger.debug "=== image_path: #{image_path&.inspect}"
begin
# Attempted to do config within controller, no difference
# Google::Cloud::Vision.configure do |config|
# config.credentials = Rails.root.join("config/credentials/google_cloud_vision.json").to_s
# end
# Check if the environment variable is set
credentials_env = ENV["GOOGLE_APPLICATION_CREDENTIALS"]
unless credentials_env
raise "Environment variable GOOGLE_APPLICATION_CREDENTIALS not set"
end
Rails.logger.debug "========== GOOGLE_APPLICATION_CREDENTIALS: #{credentials_env} =========="
####################################################
# THE NEXT LINE CRASHES THE APP SERVER EVERY TIME #########
vision_client = Google::Cloud::Vision.image_annotator
# vision_client = VisionDebug.image_annotator # Attempt to override module, see more details
Rails.logger.debug "=== vision client initialized ==="
Rails.logger.debug "#{vision_client&.inspect}"
response = vision_client.safe_search_detection image: image_path
Rails.logger.debug "=== response: #{response&.inspect}"
safe_search = response.responses.first.safe_search_annotation
Rails.logger.debug "=== safe_search: #{safe_search&.inspect}"
render json: {
adult: safe_search.adult,
violence: safe_search.violence,
}
rescue => e
# This code block is never reached, the server just crashes
error_message = "Google Cloud Vision API call failed: #{e.message}"
Rails.logger.error error_message
flash[:alert] = error_message
render :image
end
end
Backtrace
None available, just a hard stop crash of the app server.
More Details
I did somewhat successfully override the Google Cloud Vision module to inject some more debugging, which further revealed it's crashing on this line in def self.image_annotator
:
result = service_module.const_get(:Client).new(&block)
This is the full override code (just copied the original source and added a debug line in between each op):
module VisionDebug
include Google::Cloud::Vision
def self.image_annotator version: :v1, transport: :grpc, &block
Rails.logger.debug "=== image_annotator, version: #{version}, transport: #{transport}"
require "google/cloud/vision/#{version.to_s.downcase}"
Rails.logger.debug "=== after require"
package_name = Google::Cloud::Vision
.constants
.select { |sym| sym.to_s.downcase == version.to_s.downcase.tr("_", "") }
.first
Rails.logger.debug "=== package_name: #{package_name}"
service_module = Google::Cloud::Vision.const_get(package_name).const_get(:ImageAnnotator)
Rails.logger.debug "=== service_module: #{service_module&.inspect}"
service_module = service_module.const_get(:Rest) if transport == :rest
Rails.logger.debug "=== service_module after rest check: #{service_module&.inspect}"
####################################################
# THE NEXT LINE CRASHES THE APP SERVER EVERY TIME #########
result = service_module.const_get(:Client).new(&block)
# result = original_image_annotator(version, transport, &block)
Rails.logger.debug "=== Result: #{result&.inspect}"
result
end
end
The logging output of this overridden version looks like this when called from the DebugController#moderate action:
Started POST "/debug/moderate" for 127.0.0.1 at 2024-06-28 15:31:17
Processing by DebugController#moderate as HTML
Parameters: {"authenticity_token"=>"[FILTERED]", "image"=>#<ActionDispatch::Http::UploadedFile:0x000001f0bbc2aaf8 @tempfile=#<Tempfile:C:/path_to/file.jpeg>, @content_type="image/jpeg", @original_filename="file.jpeg", @headers="Content-Disposition: form-data; name=\"image\"; filename=\"file.jpeg\"\r\nContent-Type: image/jpeg\r\n">, "commit"=>"Analyze Image"}
========== DebugController#moderate...
=== image_path: "C:/path_to/Temp/RackMultipart20240628-48008-573tm7.jpeg"
========== GOOGLE_APPLICATION_CREDENTIALS: D:/path_to/config/credentials/google_cloud_vision.json ==========
=== image_annotator, version: v1, transport: grpc
=== after require
=== package_name: V1
=== service_module: Google::Cloud::Vision::V1::ImageAnnotator
=== service_module after rest check: Google::Cloud::Vision::V1::ImageAnnotator
*** CRASH BACK TO SHELL THAT APP SERVER IS RUNNING IN ***
D:\App>